2012-02-05 70 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