在iphone上通过ftp在后台上传文件



我正在尝试在应用程序中建立FTP连接。我想把几个文件上传到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];

因为主线程的运行循环已经启动并正在运行。

但相当大的文件将被上传;所以我想把工作负载放在后台线程中。但是,我如何以及在哪里设置NSRunLoop,以便在后台线程中进行整个上载?关于NSRunLoops的苹果文档(尤其是如何在不使用定时器/输入源的情况下启动它们,如本例)对我没有帮助。

我找到/创建了一个至少适合我的解决方案。使用上述方法(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服务器上创建目录。我更喜欢它,而不是其他运行循环只运行一个假定的小间隔的例子,比如1秒。

[NSDate distantFuture]

是一个未来的日期(根据苹果公司的文件,几个世纪)。但这很好,因为"中断条件"由我的类属性createdDirectory处理,或者在启动运行循环时发生错误。

我无法解释为什么它在没有明确将输入源附加到运行循环(NSTimer或NSPort)的情况下工作,但我的猜测是,NSOutputStream在后台线程的运行循环中调度就足够了(请参见createRemoteDir)。

您也可以尝试使用dispatch_async调用在后台执行createRemoteDir。它的使用要简单得多,而且您不必担心管理额外的线程。

以下是代码的样子:

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

最新更新