2012-02-05 6 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이 실행되지 않는 것입니다? 내가 메인 스레드 내부에 메시지를 보낼 경우 은 업로드가 잘 작동 : 메인 스레드의 runloop가 실행입니다

[self createRemoteDir]; 

한다.

하지만 상당히 큰 파일이 업로드됩니다. 그래서 그 작업 부하를 배경 스레드에 넣고 싶습니다. 하지만 NSRunLoop을 어떻게 그리고 어디에서 설정해야합니까? 그래서 전체 업로드가 백그라운드 스레드에서 발생합니까? NSRunLoops의 사과 문서 (특히이 경우 타이머/입력 소스를 사용하지 않고 시작하는 방법)가 도움이되지 않았습니다.

+0

나는 비슷한 질문을 여기에서 발견했다; 정말 코드가 솔루션에 대한 사용을보고 싶습니다 : [링크] (http://stackoverflow.com/questions/4930957/nsstream-and-sockets-nsstreamdelegate-methods-not-being-called) –

답변

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] 

은 미래의 날짜입니다 (몇 세기, 사과 문서에 따르면). 하지만 "break-condition"이 클래스 속성 createdDirectory에 의해 처리되거나 runloop을 시작하는 동안 오류가 발생하면 좋습니다.

입력 소스를 runloop (NSTimer 또는 NSPort)에 명시 적으로 연결하지 않고 설명 할 수는 없지만 NSOutputStream이 백그라운드 스레드의 runloop에 예약되어 있으면 충분합니다. createRemoteDir).

0

또한 dispatch_async 호출을 사용하여 백그라운드에서 createRemoteDir을 수행 할 수 있습니다. 사용하는 것이 훨씬 쉽고 추가 스레드 관리에 대해 걱정할 필요가 없습니다. 나는 /이 적어도 나를 위해 작동하는 솔루션을 개발 발견

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

가 작동하지 않습니다. , 그것은 내 접근 방식과 같은 문제가 있기 때문에 : 어떻게 NSRunLoop이 gcd 스레드에 대해 어떻게 든 구성합니까? 나는 여전히 그것을 필요로한다. (내 코드의 두번째 마지막 줄을 보아라 : [ftpStream scheduleInRunLoop : [NSRunLoop currentRunLoop] forMode : NSDefaultRunLoopMode]; 유일한 차이점은 배경 (작업자) 스레드의 생성입니다. –

+0

NSRunLoop을 구성 할 필요가 없습니다. GCD이 모든 것을 당신을 위해 해줍니다. 그것에 대해 걱정할 필요가 없습니다. –

+0

나는 그것을 시험해 보았다. 그리고 나를 위해 그것은 no go이었다 : gcd runloop을 구성하지 않았다. 그냥 performSelectorInBackground : withObject와는 다릅니다. –

관련 문제