2012-04-30 16 views
5

Có những lúc bị treo ứng dụng của tôi trước khi nó được nạp đầy đủ ngay tại dòng sau:EXC_BAD_ACCESS ngẫu nhiên với persistentStoreCoordinator

if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) 

Phương pháp hoàn chỉnh mà nếu trạng thái này nằm ngoại hình như sau (tôi nghĩ rằng đây là khá tiêu chuẩn):

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{ 
    if (__persistentStoreCoordinator != nil) { 
     return __persistentStoreCoordinator; 
    } 

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreData.sqlite"]; 

    NSError *error = nil; 
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    }  

    return __persistentStoreCoordinator; 
} 

cập nhật

Vụ tai nạn xảy ra vào thời gian thứ haiPhương thứcđược gọi. EDIT Thời gian But nó được gọi là từ viewController đầu tiên mà có thể nhìn thấy:

- (void)updateStats { 
    NSLog(@"Updating stats"); 
    dispatch_queue_t request_queue = dispatch_queue_create("updateNumberOfSchedules", NULL); 
    dispatch_async(request_queue, ^{ 
     AppDelegate *theDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; 
    [context setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]]; 
    ... 
    }); 
} 

Lần thứ hai (khi vụ tai nạn đôi khi xảy ra khi lớp DeviceLinker tôi sẽ kiểm tra các cơ sở dữ liệu cho các liên kết hoạt động trong checkInactiveLinks của tôi . phương pháp phương pháp này được gọi là khi khởi động trong applicationDidBecomeActive:

-(void) checkInactiveLinks { 
    AppDelegate *theDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 
    NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] init]; 
    [newMoc setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]]; 
    ... 
} 

đúng tôi nếu tôi sai nhưng đọc mã của tôi, tôi sẽ nghĩ rằng vào thời gian thứ hai getter persistentStoreCoordinator được gọi nó sẽ trả về __persistentStoreCoordina tor và không phân bổ và init một cái mới ...

UPDATE 2 Trên dòng chính xác cùng một lúc câu lệnh if tôi có được điều này trong từng thời kỳ quá:

-[__NSCFDictionary _hasPrecomputedKeyOrder]: unrecognized selector sent to instance 0x7dd3770 

CẬP NHẬT 3

Tôi đã chỉnh sửa sơ đồ xây dựng của mình và bật zombie và đăng nhập ngoại lệ trong tab chẩn đoán. Bây giờ tôi thấy -[NSPersistentStoreCoordinator unlock]: message sent to deallocated instance 0x8916090. Lưu ý rằng tôi không có bất kỳ khóa rõ ràng nào trong mã của mình.

+0

bạn có đang sử dụng ARC không? – mydogisbox

+0

Có gì trong nhật ký? –

+0

Bạn có đang chỉnh sửa mô hình mà không cần tạo lại phiên bản mới của mô hình trước không? –

Trả lời

19

Dường như bạn đang truy cập vào đoạn mã đó từ nhiều chuỗi cùng một lúc. Khi bạn thực hiện quá trình khởi tạo lười biếng, bạn phải đảm bảo rằng "lần đầu tiên" thông qua chỉ một chuỗi thực thi sẽ chuyển cùng một lúc. Bạn có thể sử dụng chiến lược sau đây để đồng bộ hóa quyền truy cập vào nó trên chuỗi chính.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{ 
    if (__persistentStoreCoordinator != nil) { 
     return __persistentStoreCoordinator; 
    } 

    // Add this block of code. Basically, it forces all threads that reach this 
    // code to be processed in an ordered manner on the main thread. The first 
    // one will initialize the data, and the rest will just return with that 
    // data. However, it ensures the creation is not attempted multiple times. 
    if (![NSThread currentThread].isMainThread) { 
     dispatch_sync(dispatch_get_main_queue(), ^{ 
      (void)[self persistentStoreCoordinator]; 
     }); 
     return __persistentStoreCoordinator; 
    } 

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreData.sqlite"]; 

    NSError *error = nil; 
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    }  

    return __persistentStoreCoordinator; 
} 
+2

Một dòng có thể được đơn giản hóa một chút wee: 'if (! [NSThread isMainThread]) {' –

+0

thnx buddy.You rất tuyệt. –

+0

Một lý do nữa cần phải rất cẩn thận với sự khởi tạo lười biếng. Tôi tìm thấy tôi làm chậm instantiation như tối ưu hóa sớm - thời gian để suy nghĩ lại điều đó. – Troy

1

Tôi đang sử dụng GCD để sử dụng luồng.

Và:

Có những lúc bị treo ứng dụng của tôi trước khi nó được nạp đầy đủ ngay tại dòng sau:

Âm thanh như các triệu chứng điển hình của một lỗi đồng thời có liên quan; liên tục và dường như ở sai vị trí.

CoreData có rất specific concurrency requirements. Bạn có gặp họ không?

+0

Có Tôi đọc trang web chính xác đó khi tôi bắt đầu với CoreData và bây giờ cách đây vài giờ và tôi đáp ứng các yêu cầu của họ. Chủ yếu đảm bảo bạn sử dụng MOC mới trong mỗi chuỗi và bạn có thể chia sẻ persistentStoreCoordinators. – Pieter

+0

OK - chỉ cần kiểm tra. Đồng thời là thứ phức tạp. Tuy nhiên, vẫn có thể là một vấn đề tương tranh. – bbum

0

Tôi nghĩ rằng khi bạn thêm một cửa hàng liên tục mới, trước tiên bạn nên khóa điều phối viên lưu trữ liên tục để nó không ảnh hưởng đến các cửa hàng liên tục khác.

Trong mã bên dưới psc là tham chiếu riêng cho điều phối viên lưu trữ liên tục mới được tạo. Nếu tôi hiểu đúng mục đích của bạn, phần này của phương pháp có thể là dispatch_async ed.

[psc lock]; 
if (![__persistentStoreCoordinator 
    addPersistentStoreWithType:NSSQLiteStoreType 
       configuration:nil 
          URL:storeURL 
         options:nil error:&error]) { 
    // deal with the error 
} 
[psc unlock]; 
+0

Cảm ơn bạn nhưng tôi không muốn một psc mới ... Đó là điểm lỗ, tôi muốn MOC mới trong chủ đề của tôi nhưng chia sẻ PSC, bởi vì đó là dễ dàng và đó là cách được khuyến cáo của Apple. – Pieter

+0

Nó không phải là một psc mới, chỉ là một tham chiếu đến psc hiện có. Mã này thực sự là từ Apple (nơi để chứng minh iCloud cũng là một cửa hàng liên tục phải được thêm không đồng bộ vào một psc). – Mundi

+0

Tôi đã thử nhưng có vẻ như không khắc phục được sự cố. – Pieter

1

Tôi thích khóa xoay, cách tiếp cận rõ ràng hơn gọi phương thức getter đệ quy trong chuỗi chính. Đây là giải pháp của tôi:

#import <libkern/OSAtomic.h> 

@implementation MyClass { 
    OSSpinLock _lock; 
} 

- (instancetype)init { 
    self = [super init]; 
    if (self){ 
     _lock = OS_SPINLOCK_INIT; 
    } 
} 


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{ 
    if (__persistentStoreCoordinator != nil) { 
     return __persistentStoreCoordinator; 
    } 

    // Lock the current thread 
    OSSpinLockLock(&_lock); 

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreData.sqlite"]; 

    NSError *error = nil; 
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 

    // Unlock 
    OSSpinLockUnlock(&_lock); 

    return __persistentStoreCoordinator; 
} 
+0

Lợi thế của việc sử dụng phương pháp này là gì? – Politta

+1

@Politta Cá nhân đối với tôi rõ ràng hơn, đoạn mã trên đảm bảo rằng, mọi thứ giữa 'OSSpinLockLock (& ​​_ lock);' và 'OSSpinLockUnlock (& ​​_ lock);' sẽ chỉ được truy cập bởi một chuỗi. Nếu một luồng khác cố gắng truy cập vào nó, phải đợi lệnh đầu tiên để hoàn thành việc thực thi (để đạt được 'OSSpinLockUnlock (& ​​_ lock);'). Đây là một số tài liệu 'OSSpinLockLock' https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/OSSpinLockLock.3.html Tôi hy vọng rằng tôi hữu ích. Chúc mừng –