2017-03-24 12 views
0

ファイルのダウンロードを処理する方法を以下に書いています。間違ったスレッドからアクセスされた領域

- (void)downloadFileFromURL:(NSURL *)url { 
    if (url != nil) { 
     if ([url pathExtension] != nil) { 
      RLMRealm *realm = [Utilities getRealm]; 

      RLMResults<Download *> *results = [[Download allObjectsInRealm:realm] sortedResultsUsingKeyPath:@"id" ascending:NO]; 
      Download *oldestDownload = [results firstObject]; 

      Download *download = [[Download alloc] init]; 
      download.id = oldestDownload.id+1; 
      download.name = [url path]; 
      download.type = @"html"; 
      download.state = DownloadStateNew; 
      download.token = [Utilities generateToken]; 
      download.url = [url absoluteString]; 

      [realm beginWriteTransaction]; 
      [realm addObject:download]; 
      self.current = download; 
      [realm commitWriteTransaction]; 

      NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
      NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:download.name]; 

      AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 
      manager.responseSerializer = [AFHTTPResponseSerializer serializer]; 
      manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"text/html", @"application/json", @"image/png", nil]; 
      [manager GET:[NSString stringWithFormat:@"%@", url] 
       parameters:nil 
       success:^(AFHTTPRequestOperation *operation, id responseObject) { 
        NSData *data = [[NSData alloc] initWithData:responseObject]; 
        [data writeToFile:path atomically:YES]; 
        NSLog(@"successful download to %@", path); 

        RLMRealm *realm = [Utilities getRealm]; 
        [realm beginWriteTransaction]; 
        self.current.state = DownloadStateDone; 
        [realm commitWriteTransaction]; 
       } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
        NSLog(@"Error: %@", error); 


        RLMRealm *realm = [Utilities getRealm]; 
        [realm beginWriteTransaction]; 
        self.current.state = DownloadStateCancelled; 
        [realm commitWriteTransaction]; 
       }]; 
     } 
    } 
} 

ただし、不正なスレッドからRealmにアクセスした場合、エラーが発生します。私はこれを引き起こしているのか分からない。何か案は? AFNetworkingコードから判断

+0

RealmオブジェクトまたはRealmObjectインスタンスが作成された場所とは異なるスレッドでアクセスしている可能性があります。私の推測は 'self.current.state = DownloadStateDone;'のために行われます – EpicPandaForce

+0

はい、バックグラウンドキューでコールバックブロックが呼び出されている可能性がありますが、 'self.current'プロパティには' -downloadFileFromURL: 'に呼ばれた。レルムアクセサオブジェクトはスレッド制限されているため、作成されたスレッドからのみ使用できます。 – bdash

答えて

0

は、それが元々リクエストをキックオフするために使用されたものとは別のディスパッチキューに呼び出されます両方successfailureブロックのように見えます。

ACID準拠を保証するために、Realmオブジェクトはスレッド制限されています。異なるスレッドに試行してそのプロパティにアクセスすると、例外が発生します。

// Do work with `self.current` 

RLMThreadSafeReference *currentReference = [RLMThreadSafeReference referenceWithThreadConfined:self.current]; 

AFHTTPRequestOperationManager *manager =[AFHTTPRequestOperationManager manager]; 

//Configure `manager` 

[manager GET:[NSString stringWithFormat:@"%@", url] 
    parameters:nil 
    success:^(AFHTTPRequestOperation *operation, id responseObject) { 
     MyCurrentClass *threadCurrent = [RLMRealm resolveThreadSafeReference:currentReference]; 
     [threadCurrent.realm beginWriteTransaction]; 
     threadCurrent.state = DownloadStateDone; 
     [threadCurrent.realm commitWriteTransaction]; 
    } 
    failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
     // Handle `threadReference` here too if needed 
    }]; 

は、我々は最近、それはあなたが、新しいスレッドで同じオブジェクトを照会するために使用できるレルムオブジェクトを表す、スレッドセーフな参照を渡すことが可能ですレルムのObjective-Cおよびレルムスウィフトに機能を追加しました

関連する問題