내 앱에서 일련의 다운로드 및 데이터베이스 쓰기 작업을 수행해야합니다. 내가 사용하고 NSOperation
와 NSOperationQueue
동일합니다.
이것은 애플리케이션 시나리오입니다.
- 장소에서 모든 우편 번호를 가져옵니다.
- 각 우편 번호에 대해 모든 집을 가져옵니다.
- 각 집에 대해 주민 정보를 가져옵니다.
말했듯 NSOperation
이 각 작업에 대해 정의했습니다 . 첫 번째 경우 (Task1)에서는 모든 우편 번호를 가져 오기 위해 서버에 요청을 보냅니다. 의 대리인 NSOperation
이 데이터를받습니다. 이 데이터는 데이터베이스에 기록됩니다. 데이터베이스 작업이 다른 클래스에 정의되어 있습니다. 에서 NSOperation
클래스 I 데이터베이스 클래스에 정의 된 쓰기 함수에 대한 호출을하고있다.
내 질문은 데이터베이스 쓰기 작업이 주 스레드에서 발생하는지 백그라운드 스레드에서 발생하는지 여부입니다. 내에서 호출했을 NSOperation
때 다른 스레드 (MainThread가 아님)에서 NSOperation
. 누군가 NSOperation
및을 ( 를) 다루는 동안이 시나리오를 설명해 주시겠습니까 NSOperationQueue
?
답변
내 질문은 데이터베이스 쓰기 작업이 주 스레드에서 발생하는지 백그라운드 스레드에서 발생하는지 여부입니다.
다음 NSOperationQueue
과 같이 처음부터 만드는 경우 :
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
백그라운드 스레드에 있습니다.
작업 대기열은 일반적으로 작업을 실행하는 데 사용되는 스레드를 제공합니다. OS X v10.6 이상에서 작업 대기열은 libdispatch 라이브러리 (Grand Central Dispatch라고도 함)를 사용하여 작업 실행을 시작합니다. 결과적으로 작업은 동시 또는 비 동시 작업으로 지정되었는지 여부에 관계없이 항상 별도의 스레드 에서 실행됩니다.
다음을 사용하지 않는 한 mainQueue
:
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
다음과 같은 코드도 볼 수 있습니다.
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
[myQueue addOperationWithBlock:^{
// Background work
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Main thread work (UI usually)
}];
}];
그리고 GCD 버전 :
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
{
// Background work
dispatch_async(dispatch_get_main_queue(), ^(void)
{
// Main thread work (UI usually)
});
});
NSOperationQueue
원하는 작업을보다 세밀하게 제어 할 수 있습니다. 두 작업간에 종속성을 만들 수 있습니다 (데이터베이스에 다운로드 및 저장). 한 블록과 다른 블록간에 데이터를 전달하려면 예를 들어 a NSData
가 서버에서 오는 것으로 가정 할 수 있습니다 .
__block NSData *dataFromServer = nil;
NSBlockOperation *downloadOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakDownloadOperation = downloadOperation;
[weakDownloadOperation addExecutionBlock:^{
// Download your stuff
// Finally put it on the right place:
dataFromServer = ....
}];
NSBlockOperation *saveToDataBaseOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakSaveToDataBaseOperation = saveToDataBaseOperation;
[weakSaveToDataBaseOperation addExecutionBlock:^{
// Work with your NSData instance
// Save your stuff
}];
[saveToDataBaseOperation addDependency:downloadOperation];
[myQueue addOperation:saveToDataBaseOperation];
[myQueue addOperation:downloadOperation];
편집 :__weak
작업에 대한 참조를 사용하는 이유 는 여기 에서 찾을 수 있습니다 . 그러나 간단히 말해서 유지주기를 피하는 것입니다.
답변
백그라운드 스레드에서 데이터베이스 쓰기 작업을 수행하려면 NSManagedObjectContext
해당 스레드에 대해 생성해야합니다 .
NSManagedObjectContext
관련 NSOperation
하위 클래스 의 시작 메서드에서 배경 을 만들 수 있습니다 .
핵심 데이터와의 동시성에 대한 Apple 문서를 확인하십시오 .
또한 메서드 내에서 요청 NSManagedObjectContext
을 NSPrivateQueueConcurrencyType
만들고 수행하여 자체 백그라운드 스레드에서 요청을 실행하는를 만들 수도 있습니다 performBlock:
.
답변
iOS 4 이상에서 작업 대기열은 Grand Central Dispatch를 사용하여 작업을 실행합니다. iOS 4 이전에는 비 동시 작업에 대해 별도의 스레드를 만들고 현재 스레드에서 동시 작업을 시작했습니다.
그래서,
[NSOperationQueue mainQueue] // added operations execute on main thread
[NSOperationQueue new] // post-iOS4, guaranteed to be not the main thread
귀하의 경우에는, 당신은 서브 클래스에 의해 자신의 “데이터베이스 스레드를”만들 수 있습니다 NSThread
와 함께 메시지를 보낼 performSelector:onThread:
.
답변
NSOperation의 실행 스레드 NSOperationQueue
는 작업을 추가 한 위치에 따라 다릅니다 . 당신의 코드에서이 문장을보세요-
[[NSOperationQueue mainQueue] addOperation:yourOperation]; // or any other similar add method of NSOperationQueue class
이 모든 것은 당신이 (예상되는) 작업 지침이 쓰여진 실제 괴물 인 main
방법 에서 더 이상 스레딩을 수행하지 않았다고 가정합니다 NSOperation
.
그러나 동시 작업의 경우 시나리오가 다릅니다. 큐는 각 동시 작업에 대해 스레드를 생성 할 수 있습니다. 보장되지는 않지만 시스템 리소스 대 시스템의 해당 시점 에서 운영 리소스 요구 에 따라 다릅니다 . maxConcurrentOperationCount
속성 에 따라 작업 대기열의 동시성을 제어 할 수 있습니다 .
편집 –
귀하의 질문이 흥미 롭다는 것을 알았고 직접 분석 / 로깅했습니다. 다음과 같이 주 스레드에서 NSOperationQueue를 만들었습니다.
self.queueSendMessageOperation = [[[NSOperationQueue alloc] init] autorelease];
NSLog(@"Operation queue creation. current thread = %@ \n main thread = %@", [NSThread currentThread], [NSThread mainThread]);
self.queueSendMessageOperation.maxConcurrentOperationCount = 1; // restrict concurrency
그런 다음 계속해서 NSOperation을 만들고 addOperation을 사용하여 추가했습니다. 이 작업의 주요 방법에서 현재 스레드를 확인할 때
NSLog(@"Operation obj = %@\n current thread = %@ \n main thread = %@", self, [NSThread currentThread], [NSThread mainThread]);
그것은 메인 스레드가 아닙니다. 그리고 현재 스레드 개체가 주 스레드 개체가 아님을 발견했습니다.
따라서 메인 스레드에서 큐를 사용자 지정 생성 (작업간에 동시성이 없음)한다고해서 반드시 작업이 메인 스레드 자체에서 직렬로 실행되는 것은 아닙니다.
답변
문서의 요약은 다음과 같습니다 operations are always executed on a separate thread
(iOS 4 이후에는 GCD 기본 작업 대기열을 의미 함).
주 스레드가 아닌 스레드에서 실제로 실행되고 있는지 확인하는 것은 간단합니다.
NSLog(@"main thread? %@", [NSThread isMainThread] ? @"YES" : @"NO");
스레드에서 실행할 때 GCD / libdispatch를 사용하여 기본 스레드에서 실행하는 데 필요한 핵심 데이터, 사용자 인터페이스 또는 기타 코드에 관계없이 기본 스레드에서 무언가를 실행하는 것은 간단합니다.
dispatch_async(dispatch_get_main_queue(), ^{
// this is now running on the main thread
});