1

アプリ内でFTP接続を確立しようとしています。FTPサーバーに複数のファイルをアップロードしたいのですが、すべてのファイルが1つのディレクトリにあります。だから最初に私はリモートディレクトリを作成したいと思います。

- (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];

私の推測では、(background-threads)runloopが実行されていませんか?メインスレッド内でメッセージを送信すると、アップロードは正常に機能します。

[self createRemoteDir];

メインスレッドのrunloopが稼働しているため。

ただし、かなり大きなファイルがアップロードされます。そのため、そのワークロードをバックグラウンドスレッドに配置したいと思います。しかし、アップロード全体がバックグラウンドスレッドで行われるように、NSRunLoopをどこでどのように設定すればよいですか?NSRunLoopsに関するAppleのドキュメント(特に、この場合のように、タイマー/入力ソースを使用せずにそれらを起動する方法)は私を助けませんでした。

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によって処理されるため、または実行ループの開始中にエラーが発生した場合は、これは問題ありません。

入力ソースをrunloop(NSTimerまたはNSPort)に明示的にアタッチしないと、なぜ機能するのか説明できませんが、NSOutputStreamがバックグラウンドスレッドのrunloopでスケジュールされていれば十分だと思います(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 に答える