2012-02-05 154 views
1

我試圖在應用程序內建立FTP連接。我想上傳幾個文件到一個FTP服務器,所有文件在一個目錄中。所以一開始我想創建遠程目錄。通過iPhone上的ftp在後臺上傳文件

- (void) createRemoteDir { 

    NSURL *destinationDirURL = [NSURL URLWithString: uploadDir]; 

    CFWriteStreamRef writeStreamRef = CFWriteStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) destinationDirURL); 
    assert(writeStreamRef != NULL); 

    ftpStream = (__bridge_transfer NSOutputStream *) writeStreamRef; 
    BOOL success = [ftpStream setProperty: ftpUser forKey: (id)kCFStreamPropertyFTPUserName]; 
    if (success) { 
     NSLog(@"\tsuccessfully set the user name"); 
    } 
    success = [ftpStream setProperty: ftpPass forKey: (id)kCFStreamPropertyFTPPassword]; 
    if (success) { 
     NSLog(@"\tsuccessfully set the password"); 
    } 

    ftpStream.delegate = self; 
    [ftpStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    // open stream 
    [ftpStream open]; 
} 

時在後臺線程中使用以下調用執行該代碼不起作用:

[self performSelectorInBackground: @selector(createRemoteDir) withObject: nil]; 

我的猜測是,(後臺線程)runloop沒有運行? 如果我發主線程內的信息上傳只是正常工作:

[self createRemoteDir]; 

主線程的runloop啓動並運行。

但相當大的文件將被上傳;所以我想把這個工作負載放在後臺線程中。 但我如何以及在哪裏設置NSRunLoop,以便整個上傳發生在後臺線程中?蘋果關於NSRunLoops的文檔(特別是如何在不使用定時器/輸入源的情況下啓動它們,就像這種情況一樣)沒有幫助我。

+0

我在這裏發現了一個類似的問題;我真的很想看到它的解決方案的代碼:[鏈接](http://stackoverflow.com/questions/4930957/nsstream-and-sockets-nsstreamdelegate-methods-not-being-called) – 2012-02-05 17:15:58

回答

2

我發現/創建至少對我的作品的解決方案。 上面的方法(createRemoteDir),下面的代碼應用,爲我工作:

NSError *error; 

createdDirectory = FALSE; 
/* 
only 'prepares' the stream for upload 
- doesn't actually upload anything until the runloop of this background thread is run 
*/ 
[self createRemoteDir]; 

NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; 

do { 

    if(![currentRunLoop runMode: NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]]) { 

     // log error if the runloop invocation failed 
     error = [[NSError alloc] initWithDomain: @"org.mJae.FTPUploadTrial" 
              code: 23 
             userInfo: nil]; 
    } 

} while (!createdDirectory && !error); 

// close stream, remove from runloop 
[ftpStream close]; 
[ftpStream removeFromRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode]; 

if (error) { 
    // handle error 
} 

它運行在後臺線程,並創建FTP服務器上的目錄。 我比其他例子更喜歡它,runloops只運行一個假定的小時間間隔,比如1秒。

[NSDate distantFuture] 

是在未來的幾個世紀,根據蘋果文件。但是,這是很好的,因爲「破解條件」由我的類屬性createdDirectory處理 - 或者在啓動runloop時發生錯誤。

我無法解釋爲什麼它的工作原理沒有明確地將輸入源附加到runloop(NSTimer或NSPort),但我的猜測是,只需在後臺線程的runloop中安排NSOutputStream就足夠了(請參閱createRemoteDir)。

0

您也可以嘗試使用dispatch_async調用在後臺執行createRemoteDir。使用起來更簡單,您不必擔心管理額外的線程。

下面的代碼是什麼樣子:

dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
    [self createRemoteDir]; 
}); 
+0

不起作用,因爲它與我的方法有相同的問題:我如何配置爲此gcd線程創建的NSRunLoop?我仍然需要它(見我的代碼的第二行:'[ftpStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];')。唯一不同的是創建後臺(工作者)線程 – 2012-02-05 22:45:08

+0

您不需要配置NSRunLoop。 GCD爲你做這一切。無需擔心。 – 2012-02-06 00:10:02

+0

我試過了。對我來說這是一個不行:gcd沒有配置runloop。就像performSelectorInBackground:withObject沒有。 – 2012-02-06 03:27:46