문제

나는 2 개의 nsoperations를 포함하는 nsoperationqueue를 가지고 있으며 setMaxConcurrentOperationCount 1까지.

운영 중 하나는 표준 비 콘크리트 운영입니다 ( main 방법) 웹에서 일부 데이터를 동기로 검색하는 (물론 별도의 작동 스레드에서). 다른 작업은 동시 작업입니다. 비동기 적으로 실행 해야하는 일부 코드를 사용해야하므로 동시 작업입니다.

문제는 동시 작업이 큐에 먼저 추가 된 경우에만 작동한다는 것을 발견했다는 것입니다. 비공식 작업 후에 오면 이상하게도 start 메소드가 잘라지지 만 그 메소드가 종료 된 후에는 콜백 메소드를위한 연결을 설정했지만 결코 그렇게하지 않습니다. 대기열에서 더 이상 작동하지 않습니다. 마치 시작 메소드가 돌아온 후에 매달려있는 것처럼 보이고 URL 연결에서 콜백이 호출되지 않습니다!

동시 작업이 큐에 먼저 배치되면 모두 정상적으로 작동하고 비동기 콜백이 작동하고 이후 작업이 완료된 후에 실행됩니다. 나는 전혀 이해하지 못한다!

아래의 동시 NSOperation에 대한 테스트 코드를 볼 수 있으며, 그것이 확실하다고 확신합니다.

모든 도움이 크게 감사하겠습니다!

메인 스레드 관찰 :

방금 동시 작업이 대기열에서 첫 번째라면 [start] 기본 스레드에서 메소드가 호출됩니다. 그러나 그것이 큐에서 처음이 아닌 경우 (동시 또는 동시가 아닌 경우) [start] 기본 스레드에서 메소드가 호출되지 않습니다. 이것은 내 문제의 패턴에 맞기 때문에 중요해 보입니다. 그 이유는 무엇입니까?

동시 NSOperation 코드 :

@interface ConcurrentOperation : NSOperation {
    BOOL executing;
    BOOL finished;
}
- (void)beginOperation;
- (void)completeOperation;
@end

@implementation ConcurrentOperation
- (void)beginOperation {
    @try {

        // Test async request
        NSURLRequest *r = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.google.com"]];
        NSURLConnection *c = [[NSURLConnection alloc] initWithRequest:r delegate:self];
        [r release];

    } @catch(NSException * e) {
        // Do not rethrow exceptions.
    }
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@"Finished loading... %@", connection);
    [self completeOperation];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"Finished with error... %@", error);
    [self completeOperation]; 
}
- (void)dealloc {
    [super dealloc];
}
- (id)init {
    if (self = [super init]) {

        // Set Flags
        executing = NO;
        finished = NO;

    }
    return self;
}
- (void)start {

    // Main thread? This seems to be an important point
    NSLog(@"%@ on main thread", ([NSThread isMainThread] ? @"Is" : @"Not"));

    // Check for cancellation
    if ([self isCancelled]) {
        [self completeOperation];
        return;
    }

    // Executing
    [self willChangeValueForKey:@"isExecuting"];
    executing = YES;
    [self didChangeValueForKey:@"isExecuting"];

    // Begin
    [self beginOperation];

}

// Complete Operation and Mark as Finished
- (void)completeOperation {
    BOOL oldExecuting = executing;
    BOOL oldFinished = finished;
    if (oldExecuting) [self willChangeValueForKey:@"isExecuting"];
    if (!oldFinished) [self willChangeValueForKey:@"isFinished"];
    executing = NO;
    finished = YES;
    if (oldExecuting) [self didChangeValueForKey:@"isExecuting"];
    if (!oldFinished) [self didChangeValueForKey:@"isFinished"];
}

// Operation State
- (BOOL)isConcurrent { return YES; }
- (BOOL)isExecuting { return executing; }
- (BOOL)isFinished { return finished; }

@end

대기열 코드

// Setup Queue
myQueue = [[NSOperationQueue alloc] init];
[myQueue setMaxConcurrentOperationCount:1];

// Non Concurrent Op
NonConcurrentOperation *op1 = [[NonConcurrentOperation alloc] init];
[myQueue addOperation:op1];
[op1 release];

// Concurrent Op
ConcurrentOperation *op2 = [[ConcurrentOperation alloc] init];
[myQueue addOperation:op2];
[op2 release];
도움이 되었습니까?

해결책

나는 문제가 무엇인지 발견했다!

이 둘 아주 재미있는 Dave Dribin의 기사는 동시 작업을 매우 상세하게 설명하고 Snow Leopard & The Iphone SDK가 런 루프가 필요한 것을 비동기로 부를 때 발생하는 문제를 설명합니다.

http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/ http://www.dribin.org/dave/blog/archives/2009/09/13/snowy_concurrent_operations/

올바른 방향으로 나를 지적 해 준 Chris Suter도 감사합니다!

그것의 요점은 start 메소드 우리가 메인 스레드에서 호출했습니다.

- (void)start {

    if (![NSThread isMainThread]) { // Dave Dribin is a legend!
        [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
        return;
    }

    [self willChangeValueForKey:@"isExecuting"];
    _isExecuting = YES;
    [self didChangeValueForKey:@"isExecuting"];

    // Start asynchronous API

}

다른 팁

NsurlConnection에서 문제가 발생할 가능성이 높습니다. nsurlConnection은 특정 모드를 실행하는 실행 루프 (일반적으로 기본 모드)에 따라 다릅니다.

문제에 대한 여러 가지 해결책이 있습니다.

  1. 이 작업이 기본 스레드에서만 실행되는지 확인하십시오. OS X 에서이 작업을 수행 한 경우 모든 실행 루프 모드 (예 : 모달 및 이벤트 추적 모드)에서 원하는 것을 수행하는지 확인하고 싶지만 iPhone의 거래가 무엇인지 모르겠습니다.

  2. 자신의 스레드를 만들고 관리합니다. 좋은 해결책이 아닙니다.

  3. 호출 -[nsurlConnection ScheduleInRunLoop : 포모드 :] 메인 스레드 또는 다른 스레드를 전달하십시오. 이렇게하면 호출하고 싶을 것입니다 -[NSURLCONNECTION UNSCHEDULUNLOOP : FORMODE :] 먼저 여러 스레드에서 데이터를 수신 할 수 있습니다 (또는 적어도 문서가 제안하는 것).

  4. +[nsdata datawithcontentsofurl : 옵션 : 오류 :]와 같은 것을 사용하면 대신 비 일치하는 작업으로 만들 수 있으므로 작동을 단순화합니다.

  5. #4의 변형 : 사용 +[nsurlConnection sendsynchronousRequest : returningResponse : error :].

도망 갈 수 있다면 #4 또는 #5를하십시오.

나는 눈치 채지 못했고 언급하지도 않았다. addDependency:, 이는 적절한 순서로 운영을 실행하는 전제 조건처럼 보입니다.

요컨대, 두 번째 작업은 첫 번째 작업에 따라 다릅니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top