2010-08-05 5 views
6

저는 현재 iPhone 앱에서 작업하고 있으며 비동기 동작이 있지만 제 클래스로 랩핑하여 동기식으로 나타나게하려는 써드 파티의 라이브러리가 있습니다.동기식 클래스를 래핑하여 동기시키는 방법은 무엇입니까? NSRunLoop을 사용 하시겠습니까?

이 라이브러리의 중앙 클래스는 Connection 클래스라고 부르겠습니다. 위임 클래스 인스턴스의 메서드를 호출 할 때 궁극적 인 결과가 확인되는 여러 함수가 있습니다. 내가 뭘 하려는지이 클래스를 랩하고 비동기가 아닌 동기식으로 표시되도록 위임하는 것입니다. Java에서이 작업을 수행하는 경우 FutureTask 또는 CountdownLatch를 사용하거나 join()을 사용합니다. 그러나 Objective C에서이 작업을 수행하는 가장 좋은 방법은 확실하지 않습니다.

위에서 설명한 위임 프로토콜을 준수하는 NSThread 확장 인 NFCThread를 작성하여 시작했습니다. NFCThread 인스턴스를 Connection의 setDelegate 메서드에 전달하고 스레드를 시작한 다음 Connection에서 비동기 메서드를 호출한다는 아이디어가 init과 NFCThread입니다. 내 기대는 NFCThread 인스턴스의 세 대리자 메서드 중 하나가 궁극적으로 스레드가 종료되도록 호출됩니다.

조인을 시뮬레이트하려면 다음을 수행했습니다. 나는 NFCThread에 NSConditionalLock 추가 :

NFCThread *t = [[NFCThread alloc] init]; 
[connection setDelegate:t]; 
[t start]; 

[connection openSession]; 
// Process errors, etc... 

[t.joinLock lockWhenCondition:YES]; 
[t.joinLock unlock]; 
[t release]; 
[connection setDelegate:nil]; 

대리인의 프로토콜은 세 가지 방법이 있습니다

joinLock = [[NSConditionLock alloc] initWithCondition:NO]; 

연결에 대한 호출 주변의 코드는 다음과 같이 보입니다.

- (void)didReceiveMessage:(CommandType)cmdType 
        data:(NSString *)responseData 
       length:(NSInteger)length { 
    NSLog(@"didReceiveMessage"); 
    // Do something with data and cmdType... 
    [joinLock lock]; 
    [joinLock unlockWithCondition:YES]; 
    callBackInvoked = YES; 
} 

그냥 계속 루프 그래서 내가 NFCThread의 주요 메소드를 오버로드 : NFCThread에서이 같은 각각의 방법에 뭔가를 구현했습니다. 다음과 같은 것 :

while (!callBackInvoked) { ; } 

이것은 CPU 사용이 지붕을 통과하기 때문에 실제로는 좋은 생각이 아닙니다. 그래서 그 대신 나는이 사이트에서 발견 된 일부 예에서 실행 루프를 사용하여 시도 내 구현 모두에서

NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; 

while (!callBackInvoked) { 
    [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
} 

를 메인 스레드가 항상 차단하고 위임 방법 중 어느 것도 지금까지 호출되지 것을 나타납니다. 그러나 라이브러리가 제대로 작동하고 대리자 메서드에 대한 호출이 정상적으로 호출된다는 것을 알고 있습니다.

나는 여기서 명백한 것을 놓치고있는 것처럼 느낍니다. 어떤 도움을 많이 주셨습니다.

리치

답변

0

좋아, 여기에 몇 가지 다른 문제가 있으므로 어디서부터 시작해야할지 생각하고 있습니다.

하지만 우리는 당신이 달성하려는 것을 이해하고 있습니다. 즉, 호출이 동기식으로 나타나기를 원한다고 말하면 호출을 차단하겠습니까? 메인 스레드에서이 호출을하고 있습니까?그렇다면 디자인을 통해 주 스레드를 차단하고있는 것으로 보입니다.

제 3 자 라이브러리가 주 실행 루프의 이벤트를 예약하고있는 것입니다. 자체 실행 루프를 작성하여 다른 스레드에서 실행할 수 있지만 다른 라이브러리에 해당 실행 루프를 해당 이벤트에 사용하도록 지시 했습니까? (예를 들어, 차단 한 기본 실행 루프에서 예약 된 비동기 네트워크 요청을 만들 수 있습니다.)

나는 약간의 일을 다시 생각하지만 처음에는 의도가 무엇인지 알 필요가 있습니다. 이 호출을하고있는 스레드를 차단합니다. 또한 iPhoneOS 3.x를 지원해야합니까?

+0

고마워, 피로스. 예, Google의 동기 호출을 차단하려고합니다. 이 제 3 자 라이브러리는 실제로 SD 카드와 인터페이스하지만, 이는 단지 세부 사항이라고 생각합니다. 또한 자세히 살펴보면 위임 메서드에 대한 호출이 주 스레드에서도 발생하는 것으로 확인되었습니다. 이게이 모든 토론을 부인할 수 있겠습니까? – richever

+1

글쎄, 나는 그것이 의의가 있는지 모르겠다. 문제는 호출을 차단하고 기본 스레드를 차단하려는 경우이 다른 라이브러리가 작업을 완료 할 수 없다는 것입니다. 하나의 대답은 다른 스레드에서 동기 호출을 만들어 * thread를 차단하지만 주 스레드가 계속 정상적으로 작동하도록 허용하는 것입니다. 물론이 방법으로 많은 스레드를 만들고 차단하면 결국 좋지 않습니다. 어쨌든, 나는 * 왜 * 당신이이 동기화를 원하고 아마도 같은 것을하기위한 비 차단 방법을 생각할 것인가? (당신이 여기서하려고하는 것을 더 많이 알 필요가있다.) –

+0

나는 블로킹 방법을 호출하고있다. Firoze를 제안한 것처럼 지금은 다른 스레드에서 작동합니다. 일종의. 내 다음 질문을 참조하십시오. http://stackoverflow.com/questions/3444557/error-at-nsrunloop-after-returning-from-thread-method-with-nsautoreleasepool – richever

4

당신은 비동기 콜백이 세마포어를 신호하고 계속할 수 있습니다 때까지 기본 코드 경로 차단 할 수 세마포어를 원한다.

세마포는 Grand Central Dispatch를 통해 iOS 4에서 사용할 수 있습니다.

세마포어의 동작은 NSCondition이있는 iOS 3에서 구현 될 수 있습니다.

+0

감사합니다. Seamus,하지만 불행히도이 질문에서 언급 한 라이브러리는 3.x로 컴파일되었으므로 afaik, 우리는 GCD를 사용할 수 없습니다. 다른 제안? – richever

2

방금 ​​비슷한 것을 구현했습니다. 컨텍스트는 다음과 같습니다. - 배경 스레드에서 ZipArchive에 대한 여러 호출을 묶습니다. - 압축 해제 할 때마다 다른 진행률 표시기 (확장중인 파일의 이름이있는 무한 회전 휠) - 모든 작업이 완료되면 정리 작업을 수행하십시오.

NSConditionLock* lock = alloc/init 
for(int idx = 0; idx < [list count]; idx++) { 
    NSString* fileName = ["getIdx's element in list"] 
    [cond lockWhenCondition:idx]; // 

    ... prepare things before forking 

    [cond unlockWithCondition:-1]; 
    [Notification forkBlock:^(void){ 
    [cond lockWhenCondition:-1]; 

    NSAutoreleasePool *pool = [alloc/init]; 
    [ZipArchive unzipFile:fileName]; 
    [pool release]; 
    [cond unlockWithCondition:idx+1]; 
    }]; 
} 

[cond lockWhenCondition:[list count]; 
// all the tasks are now completed 

블록 각각은 백그라운드 스레드에서 예정 : 아카이브

이 NSConditionLock 그것은 간단하게 밝혀, 다음과 같이 코드가 작동

을 확대하고있다. Notification 클래스는 회전하는 바퀴로 UIView에 애니메이션을 적용하고 다른 스레드에서 블록을 래핑합니다. 잠금/잠금 해제는 같은 스레드에서 호출해야하므로 조건은 배경 스레드와 배경 스레드 사이의 핑퐁을 가능하게합니다 (배경의 경우 -1, 전경의 경우 1,2,3 .. n).

0

NSCondition을 사용하여 현재 스레드에서 대기하고 두 번째 스레드에서 신호를 보내서 첫 번째 스레드가 계속 진행되도록 할 수 있습니다.

- (void) firstThread 
{ 
    workIsDone = NO; 
    //Start second thread here 
    [condition lock]; 
    while (!workIsDone) { 
     [condition wait]; 
    } 
    [condition unlock]; 

    // Keep going 
} 

- (void) secondThread 
{ 
    [condition lock]; 

    //Do some work. 
    workIsDone = YES; 
    [condition signal]; 
    [condition unlock]; 
} 
관련 문제