2012-01-20 12 views
0

トピックの状態のように - 別のスレッドでNSManagedObjectを更新しようとしています。 私のiPhoneアプリが複数のAssetをダウンロードしていて、指定されたオブジェクトのdownloadStatusを更新したいとします。 2つの異なるスレッドのために私は新しいNSManagedObjectContextを作成してmainメソッドの資産を私のNSOperation/ASIHTTPRequestにフェッチします。ASIHTTPRequest /バックグラウンドスレッドでNSManagedObjectを更新しようとしています

最初の1-n Assetは問題なくダウンロードされますが、コンテキストを保存しようとしているうちにEXC_BAD_ACCESSが表示されます。ここ

は私のコード

AssetDownload.h

#import "ASIHTTPRequest.h" 

@interface AssetDownload : ASIHTTPRequest 
{ 
    @private 
    Asset *_tempAsset; 
    NSManagedObjectID *_assetId; 
    NSManagedObjectContext *_ctx; 
} 

@property (nonatomic, strong) NSManagedObjectID *assetId; 
@property (nonatomic, strong) NSManagedObjectContext *ctx; 

- (id) initWithURL:(NSURL *)assetUrl andAsset:(NSManagedObjectID *)assetId; 
+ (id) requestWithURL:(NSURL *)newURL andAsset:(NSManagedObjectID *)assetId; 

@end 

とAssetDownload.m

#import "AssetDownload.h" 
#import "DataController.h" 

@interface AssetDownload (Private) 
- (void) checkArticleStatusForAsset; 
@end 

@implementation AssetDownload 

@synthesize assetId=_assetId; 
@synthesize ctx=_ctx; 

- (id) initWithURL:(NSURL *)assetUrl andAsset:(NSManagedObjectID *)assetId 
{ 
    self = [self initWithURL:assetUrl]; 
    if (self) 
    { 
     self.assetId = assetId; 
    } 

    return self; 
} 

// 
- (void) main 
{ 
    // CORE DATA & MULTITHREADING 
    _ctx = [[NSManagedObjectContext alloc] init]; 
    [self.ctx setUndoManager:nil]; 
    [self.ctx setPersistentStoreCoordinator: [[DataController sharedInstance] persistentStoreCoordinator]]; 

    // Register context with the notification center 
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
    [nc addObserver:self 
      selector:@selector(mergeChanges:) 
       name:NSManagedObjectContextDidSaveNotification 
      object:self.ctx]; 

    // get the asset from temp managedContext 
    NSError *err; 
    _tempAsset = (Asset *) [self.ctx existingObjectWithID:self.assetId error:&err]; 
    if (_tempAsset == nil) 
    { 
     // asset not found 
     NSLog(@"download asset data not found in CoreData - cancel download"); 
     return; 
    } 

    if ([_tempAsset isAvailable]) 
    { 
     NSLog(@"AssetDownload main() >>> already downloaded -> COMPLETE"); 
     complete = YES; 
     [self markAsFinished]; 
     [self checkArticleStatusForAsset]; 
     return; 
    } 

    NSLog(@"AssetDownload main() >>> download");  
    [super main]; 
} 

// 
- (void) requestFinished 
{ 
    NSLog(@"AssetDownload requestFinished() >>> %i", self.responseStatusCode); 

    NSError *mError; 
    NSFileManager *fmngr = [NSFileManager defaultManager]; 
    if (self.responseStatusCode == 200) 
    { 
     if ([fmngr moveItemAtPath:self.downloadDestinationPath toPath:_tempAsset.localPath error:&mError]) 
     { 
      NSLog(@"file moved: %@", _tempAsset.localPath); 
      _tempAsset.downloadStatus = DownloadStatusComplete; 
      [self checkArticleStatusForAsset]; 
     } 
     else 
     { 
      NSLog(@"ERROR file not moved: %@ ... %@", _tempAsset.localPath, mError); 
      _tempAsset.downloadStatus = DownloadStatusError; 
     } 
    } 
    else 
    { 
     [fmngr removeItemAtPath:self.downloadDestinationPath error:nil]; 
     _tempAsset.downloadStatus = DownloadStatusError; 
    } 

    NSError *sError; 
    [self.ctx save:&sError]; 

    [super requestFinished]; 
} 


// 
- (void) failWithError:(NSError *)theError 
{ 
    NSLog(@"AssetDownload failWithError() >>> %@", theError); 
    _tempAsset.downloadStatus = DownloadStatusError; 

    [self.ctx save:nil]; 

    [super failWithError:theError]; 
} 


// 
- (void) checkArticleStatusForAsset 
{ 
    if (_tempAsset.article.isLoaded) 
    { 
     NSDictionary *info = [NSDictionary dictionaryWithObject:_tempAsset.article forKey:@"article"]; 
     [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationArticleAssetsLoaded 
                  object:self 
                  userInfo:info]; 
    } 
} 


#pragma mark - 

- (void) mergeChanges:(NSNotification *)notification 
{ 
    if ([notification object] == self.ctx) 
    { 
     NSLog(@"MERGE !"); 

     NSManagedObjectContext *mainContext = [[DataController sharedInstance] managedObjectContext]; 

     // Merge changes into the main context on the main thread 
     [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
             withObject:notification 
            waitUntilDone:YES]; 
    } 
} 


#pragma mark - 


// 
+ (id) requestWithURL:(NSURL *)newURL andAsset:(NSManagedObjectID *)assetId andManager:(AssetManager*)manager 
{ 
    return [[self alloc] initWithURL:newURL andAsset:assetId andManager:manager]; 
} 

@end 

であり、これはエラーが

NSError *sError; 
[self.ctx save:&sError]; 
requestFinished:に)起こる場所です

誰かが私になぜこれが起こっているのか説明することができます!

答えて

0

私はすべてをリファクタリングし、更新をAssetクラスに移動しました。

の代わりに、そのObjectIDAssetを取得私はちょうどAssetDownloadクラスにそれを渡し、

- (void) updateDownloadStatus:(TCRDownloadStatus)status 
{ 
    NSNumber *statusNum = [NSNumber numberWithInt:status]; 
    [self.asset performSelectorOnMainThread:@selector(updateDownloadStatus:)  
           withObject:statusNum 
           waitUntilDone:YES]; 
} 

たび、ステータスの変更を行います。

これまでのところすごくうまくいっていて、以前よりはるかに少ないコードです。

関連する問題