2012-01-20 16 views
0

像主題狀態 - 我試圖更新另一個線程中的NSManagedObject。 我的iPhone應用程序正在下載多個Asset並且想要更新給定對象的downloadStatus。由於兩個不同的線程,我創建了一個新的NSManagedObjectContext並獲取我的NSOperation/ASIHTTPRequestmain方法中的資產。試圖更新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 

,這是在錯誤發生(在requestFinished:

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

也許有人可以向我解釋爲什麼會發生這種情況!?

回答

0

好吧,我重構了整個事情,並將更新移至Asset類。

,而不是獲取的AssetObjectID我只是把它傳遞到AssetDownload類,做一個

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

時的狀態變化。

迄今爲止效果很好,而且代碼比以前少得多:)