2012-06-11 24 views
5

Đây là câu hỏi đầu tiên của tôi về Stack Overflow, vì vậy hãy tha thứ cho tôi nếu tôi vi phạm bất kỳ nghi thức nào. Tôi cũng khá mới để tạo Objective-C/app.UIManagedDocument chèn các đối tượng trong chủ đề nền

Tôi đã theo khóa học CS193P Stanford, đặc biệt là các bài giảng/trình diễn CoreData. Trong ứng dụng Photomania của Paul Hegarty, ông bắt đầu với một cái nhìn bảng, và điền dữ liệu vào nền, mà không có bất kỳ sự gián đoạn nào đối với luồng giao diện người dùng. Tôi đã tạo một ứng dụng liệt kê các doanh nghiệp trong khu vực địa phương (từ một api trả về dữ liệu JSON).

Tôi đã tạo các danh mục theo lớp ảnh/nhiếp ảnh gia của Paul. Việc tạo ra các lớp học không phải là một vấn đề, đó là nơi chúng được tạo ra.

A simplified data structure: 
- Section 
    - Sub-section 
     - business 
     - business 
     - business 
    - business 
    - business 
    - business 

Ứng dụng của tôi bắt đầu với một UIViewController với một vài nút, mỗi trong số đó sẽ mở ra một tableview cho phần tương ứng (những tất cả hoạt động tốt, tôi đang cố gắng để cung cấp đủ thông tin để câu hỏi của tôi có ý nghĩa). Tôi gọi phương thức trợ giúp để tạo/mở URL cho UIManagedDocument, được dựa trên this question. Điều này được gọi ngay sau khi ứng dụng chạy, và nó tải lên nhanh chóng.

Tôi có một phương pháp rất giống với fetchFlickrDataIntoDocument Phaolô:

-(void)refreshBusinessesInDocument:(UIManagedDocument *)document 
{ 
dispatch_queue_t refreshBusinessQ = dispatch_queue_create("Refresh Business Listing", NULL); 
dispatch_async(refreshBusinessQ, ^{ 
    // Get latest business listing 
    myFunctions *myFunctions = [[myFunctions alloc] init]; 
    NSArray *businesses = [myFunctions arrayOfBusinesses]; 

    // Run IN document's thread 
    [document.managedObjectContext performBlock:^{ 

     // Loop through new businesses and insert 
     for (NSDictionary *businessData in businesses) { 
      [Business businessWithJSONInfo:businessData inManageObjectContext:document.managedObjectContext]; 
     } 

     // Explicitly save the document. 
     [document saveToURL:document.fileURL 
      forSaveOperation:UIDocumentSaveForOverwriting 
      completionHandler:^(BOOL success){ 
       if (!success) { 
        NSLog(@"Document save failed"); 
       } 
      }]; 
     NSLog(@"Inserted Businesses"); 
    }]; 
}); 
dispatch_release(refreshBusinessQ); 
} 

[myFunctions arrayOfBusinesses] chỉ phân tích các dữ liệu JSON và trả về một NSArray chứa businessses cá nhân.

Tôi đã chạy mã bằng NSLog ở đầu và cuối mã tạo doanh nghiệp. Mỗi doanh nghiệp được chỉ định một phần, mất 0,006 giây để tạo và có hàng trăm trong số này. Chèn sẽ kết thúc trong khoảng 2 giây.

Các Helper Method là ở đây:

// The following typedef has been defined in the .h file 
// typedef void (^completion_block_t)(UIManagedDocument *document); 

@implementation ManagedDocumentHelper 

+(void)openDocument:(NSString *)documentName UsingBlock:(completion_block_t)completionBlock 
{ 
    // Get URL for document -> "<Documents directory>/<documentName>" 
    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
    url = [url URLByAppendingPathComponent:documentName]; 

    // Attempt retrieval of existing document 
    UIManagedDocument *doc = [managedDocumentDictionary objectForKey:documentName]; 

    // If no UIManagedDocument, create 
    if (!doc) 
    { 
     // Create with document at URL 
     doc = [[UIManagedDocument alloc] initWithFileURL:url]; 

     // Save in managedDocumentDictionary 
     [managedDocumentDictionary setObject:doc forKey:documentName]; 
    } 

    // If the document exists on disk 
    if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]]) 
    { 
     [doc openWithCompletionHandler:^(BOOL success) 
     { 
      // Run completion block 
      completionBlock(doc); 
     } ]; 
    } 
    else 
    { 
     // Save temporary document to documents directory 
     [doc saveToURL:url 
     forSaveOperation:UIDocumentSaveForCreating 
    completionHandler:^(BOOL success) 
     { 
      // Run compeltion block 
      completionBlock(doc); 
     }]; 
    } 
} 

Và được gọi trong viewDidLoad:

if (!self.lgtbDatabase) { 
    [ManagedDocumentHelper openDocument:@"DefaultLGTBDatabase" UsingBlock:^(UIManagedDocument *document){ 
     [self useDocument:document]; 
    }]; 
} 

useDocument chỉ đặt self.document vào tài liệu được cung cấp.

Tôi muốn thay đổi mã này để dữ liệu được chèn vào một chuỗi khác và người dùng vẫn có thể nhấp vào nút để xem phần mà không nhập dữ liệu treo giao diện người dùng.

Bất kỳ trợ giúp nào sẽ được đánh giá cao Tôi đã làm việc về vấn đề này trong một vài ngày và không thể giải quyết nó, ngay cả với các câu hỏi tương tự khác trên đây. Nếu có bất kỳ thông tin nào khác mà bạn yêu cầu, vui lòng cho tôi biết!

Cảm ơn bạn

EDIT:

Cho đến nay câu hỏi này đã nhận được một xuống bỏ phiếu. Nếu có một cách để tôi có thể cải thiện câu hỏi này, hoặc ai đó biết về một câu hỏi mà tôi không thể tìm thấy, bạn có thể vui lòng bình luận như thế nào hoặc ở đâu? Nếu có một lý do khác mà bạn đang downvoting, xin vui lòng cho tôi biết, như tôi không thể hiểu được tiêu cực, và rất thích tìm hiểu làm thế nào để đóng góp tốt hơn.

Trả lời

11

Có một vài cách để làm điều này.

Vì bạn đang sử dụng UIManagedDocument, bạn có thể tận dụng lợi thế của NSPrivateQueueConcurrencyType để khởi tạo NSManagedObjectContext mới và sử dụng performBlock để thực hiện công cụ của mình. Ví dụ:

// create a context with a private queue so access happens on a separate thread. 
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
// insert this context into the current context hierarchy 
context.parentContext = parentContext; 
// execute the block on the queue of the context 
context.performBlock:^{ 

     // do your stuff (e.g. a long import operation) 

     // save the context here 
     // with parent/child contexts saving a context push the changes out of the current context 
     NSError* error = nil; 
     [context save:&error]; 
}]; 

Khi bạn lưu từ ngữ cảnh, dữ liệu của ngữ cảnh riêng tư được đẩy đến ngữ cảnh hiện tại. Tiết kiệm chỉ hiển thị trong bộ nhớ, vì vậy bạn cần truy cập vào ngữ cảnh chính (ngữ cảnh được liên kết với UIDocument) và lưu ở đó (xem does-a-core-data-parent-managedobjectcontext-need-to-share-a-concurrency-type-wi).

Cách khác (yêu thích của tôi) là tạo một lớp con NSOperation và làm công cụ ở đó. Ví dụ, khai báo một lớp con NSOperation như sau:

//.h 
@interface MyOperation : NSOperation 

- (id)initWithDocument:(UIManagedDocument*)document; 

@end 

//.m 
@interface MyOperation() 

@property (nonatomic, weak) UIManagedDocument *document; 

@end 

- (id)initWithDocument:(UIManagedDocument*)doc; 
{ 
    if (!(self = [super init])) return nil; 

    [self setDocument:doc]; 

    return self; 
} 

- (void)main 
{ 
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init]; 
    [moc setParentContext:[[self document] managedObjectContext]]; 

    // do the long stuff here... 

    NSError *error = nil; 
    [moc save:&error]; 

    NSManagedObjectContext *mainMOC = [[self document] managedObjectContext]; 
    [mainMOC performBlock:^{ 
    NSError *error = nil; 
    [mainMOC save:&error]; 
    }]; 

    // maybe you want to notify the main thread you have finished to import data, if you post a notification remember to deal with it in the main thread... 
} 

Bây giờ trong các chủ đề chính, bạn có thể cung cấp cho hoạt động đó để một hàng đợi như sau:

MyOperation *op = [[MyOperation alloc] initWithDocument:[self document]]; 
[[self someQueue] addOperation:op]; 

T.B. Bạn không thể bắt đầu hoạt động không đồng bộ trong phương thức main của NSOperation. Khi kết thúc main, các đại biểu được liên kết với các hoạt động đó sẽ không được gọi. Để nói sự thật bạn có thể nhưng điều này liên quan đến việc đối phó với vòng lặp chạy hoặc hành vi đồng thời.

Hy vọng điều đó sẽ hữu ích.

+2

Bạn là một huyền thoại tuyệt đối! Tôi đã sử dụng giải pháp đầu tiên của bạn, như với tôi nó có vẻ đơn giản để hiểu. Thật không may tôi không thể cung cấp cho bạn upvote bạn xứng đáng cho điều này vì tôi chỉ mới tham gia, nhưng khi tôi có thể tôi sẽ. Tôi sẽ xem xét NSOperations vào một ngày sau đó, vì điều đó làm tôi bối rối một chút. Một lần nữa, cảm ơn rất nhiều vì sự giúp đỡ của bạn! –

+0

Bạn được chào đón. Chúc mừng. –

+2

Chỉ để hoàn thành: Đừng quên nói với UIManagedDocument rằng nó đang ở trạng thái bẩn sau khi hoạt động (và mọi thứ khác) của bạn. Vì vậy, hãy buộc lưu bằng cách gọi '[document updateChangeCount: UIDocumentChangeDone]'. Đây là những gì còn thiếu trong khóa học CS193P Stanford. –

0

Ban đầu tôi chỉ để lại nhận xét, nhưng tôi đoán tôi không có đặc quyền cho nó. Tôi chỉ muốn chỉ ra những UIDocument, ngoài số lượng thay đổi cung cấp - (void)autosaveWithCompletionHandler:(void (^)(BOOL success))completionHandler

nào không nên có sự chậm trễ tôi đã có kinh nghiệm với việc cập nhật số lượng thay đổi vì nó chờ đợi một "thời điểm thuận tiện".

+0

đây không phải là câu trả lời – johannes

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