2012-01-20 2 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 

이며,이 오류가

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]; 
} 

때마다 상태 변경을한다.

위대한 작품 ... 이전보다 훨씬 적은 코드 :)

관련 문제