5

Tôi có hình ảnh trong coredata mà tôi đang cố gắng tải một cách lười biếng cho chế độ xem bảng. Mỗi ô sử dụng một người quan sát cho thực thể dữ liệu cốt lõi có liên quan để cập nhật hình ảnh khi có sẵn. Các mã có liên quan trong tổ chức thực hiện như sau:Nhận EXC_BAD_ACCESS khi sử dụng dispatch_async với Dữ liệu chính

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    // The heavy lifting seems to be during firing of the fault and accessing data, 
    // so i'm trying to do that in the background thread. 
    UIImage *i = [UIImage imageWithData:self.imageEntity.data]; 
    // I now need to notify observers that the image is ready on the main thread 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    [self willChangeValueForKey:@"image"]; 
    image = i; 
    [self didChangeValueForKey:@"image"]; 
    }); 
}); 

Dự án sử dụng ARC, tôi không nhận được bất kỳ lỗi biên dịch hoặc cảnh báo, và khi tôi chạy nó loại công trình cho đến khi tôi di chuyển nhanh chóng, và sau đó tôi nhận được một EXC_BAD_ACCESS trên dòng khi tôi tuyên bố i.

Tôi thiếu gì ở đây?

+0

Bạn đã thử với 'NSZombieEnabled' chưa? – zoul

+0

điều gì xảy ra nếu bạn không sử dụng dispatch_async? chỉ chạy trên chủ đề chính –

+0

NSZombie không làm giảm thêm bất kỳ ánh sáng nào cho tôi. Nếu tôi không dispatch_async nó sẽ chặn các chủ đề chính và di chuyển thực sự kém. – dizy

Trả lời

7

Dường như tìm nạp CoreData objects is not thread safe. Vì vậy, nó được đề nghị sử dụng cùng một persistentStoreCoordinator, nhưng khác nhau ObjectContexts. Đây là mã cập nhật của tôi không còn dường như sụp đổ:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    @autoreleasepool { 
    // Create a new context 
    NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] init]; 
    // Use an existing coordinator 
    NSPersistentStoreCoordinator *coordinator = [[DataSource sharedDataSource] persistentStoreCoordinator]; 
    [backgroundContext setPersistentStoreCoordinator:coordinator]; 
    // Getting objectID does not fire the fault, so we grab it but actually fetch the object 
    // on a background context to be thread safe. 
    Image *imageEntity = (Image*)[backgroundContext objectWithID:self.imageEntity.objectID]; 
    image = [UIImage imageWithData:imageEntity.data]; 
    // Notify observers that the image is ready on the main thread 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self willChangeValueForKey:@"image"]; 
     [self didChangeValueForKey:@"image"]; 
    }); 
    } 
}); 
+0

Sau đó bạn có thể lưu hình ảnh trên luồng chính, trong ngữ cảnh đối tượng được quản lý ứng dụng không? Làm thế nào bạn sẽ làm điều này, vì nó đã được tạo ra trên các chủ đề nền? – SAHM

1

Dizy, cũng cần lưu ý rằng đối tượng hình ảnh được tạo ra trong các mã:

UIImage *i = [UIImage imageWithData:self.imageEntity.data]; 

được thiết lập cho autorelease. Phương thức dispatch_async chạy trên hàng đợi chính, vì vậy có khả năng bộ nhớ được cấp phát cho hình ảnh có thể được giải phóng vào thời điểm luồng chính chạy khối công văn.

+0

Điểm tốt, tôi chỉ cần bọc toàn bộ nội dung trong @autoreleasepool {} để giải quyết điều đó? – dizy

+0

Tôi sẽ giữ lại hình ảnh trong khối ngoài rồi nhả nó trong khối bên trong. –

+0

Tôi đang sử dụng ARC trong dự án – dizy

0

CoreData không phải là chủ đề an toàn, bạn phải quản lý các ngữ cảnh để tránh sự cố. Nếu bạn định sử dụng nhiều quá trình đồng thời để cập nhật dữ liệu trong Dữ liệu cốt lõi, tôi khuyên bạn hãy xem MagicalRecord, một mẫu tuyệt vời lấy cảm hứng từ Active Record of Rails và xử lý tất cả các khía cạnh này một cách thực sự thông minh .

+0

Cảm ơn bạn đã chỉ ra MagicalRecord, âm thanh khá tuyệt vời. – dizy

Các vấn đề liên quan