1

我正在尝试在应用程序中建立 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];

我的猜测是(后台线程)运行循环没有运行?如果我在主线程内发送消息,则上传工作正常:

[self createRemoteDir];

由于主线程的运行循环已启动并正在运行。

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

4

2 回答 2

3

我找到/创建了一个至少对我有用的解决方案。使用上述方法(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]

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

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

于 2012-02-06T03:25:57.737 回答
0

您还可以尝试使用 dispatch_async 调用在后台执行您的 createRemoteDir。它使用起来更简单,您不必担心管理额外的线程。

下面是代码的样子:

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    [self createRemoteDir];
});
于 2012-02-05T19:46:40.360 回答