2013-03-05 29 views
5

Tôi có ứng dụng dựa trên UIDocument sử dụng NSFileWrapper giây để lưu trữ dữ liệu. Trình bao bọc tệp 'master' chứa nhiều trình bao bọc tệp thư mục bổ sung, mỗi tệp trình bày một trang khác của tài liệu.UIDocument & NSFileWrapper - NSFastEnumerationMutationHandler trong khi thay đổi tệp trình bao bọc trong khi lưu

Bất cứ khi nào tôi thực hiện thay đổi đối với tài liệu trong khi UIDocument đang lưu (trong writeContents:andAttributes:safelyToURL:forSaveOperation:error:), ứng dụng gặp sự cố. Dưới đây là stack trace:

UIDocument crash stack trace

Có vẻ như rõ ràng rằng tôi đang thay đổi cùng một ví dụ của tập tin wrapper rằng UIDocument được liệt kê trên ở chế độ nền. Thật vậy, tôi đã kiểm tra rằng khi trả về ảnh chụp nhanh của mô hình dữ liệu trong contentsForType:error:, hàm đóng tệp phụ được trả về trỏ đến cùng một đối tượng như những đối tượng hiện đang cư trú (và đang được chỉnh sửa) trong mô hình dữ liệu chứ không phải bản sao.

- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError 
{ 
    if (!_fileWrapper) { 
     [self setupEmptyDocument]; 
    } 
    return [[NSFileWrapper alloc] initDirectoryWithFileWrappers:[_fileWrapper fileWrappers]]; 
} 

Đây là phương pháp bị xử phạt để thực hiện phương pháp này (theo WWDC 2012 Session 218 - Using iCloud with UIDocument).

Vì vậy, tôi cho rằng câu hỏi là: Cách tiếp cận này có thể là chuỗi an toàn không?

Tình huống có khác biệt nào khi trình bao bọc tệp chính fileWrappers là các trình bao bọc tệp thư mục của chúng không? Nếu cách tiếp cận bị xử phạt sai, làm cách nào nên nó được thực hiện?

+0

Tôi chưa gặp phải tình huống này, nhưng có vẻ như NSFileCoordinator có thể thực hiện công việc? –

+0

@MikeM Bạn có thể đúng ở chỗ nó sẽ ngăn chặn sự cố, nhưng tôi lo lắng rằng nó có tiềm năng thực sự làm chậm mọi thứ. Thông thường, các bản cập nhật trong ứng dụng nhỏ và thường xuyên và cần phải có nội dung cập nhật để ứng dụng luôn đáp ứng. Tôi sẽ phải điều tra cách tiếp cận này hơn nữa và xem liệu nó có khả thi hay không. Tuy nhiên câu hỏi vẫn còn - là cách tiếp cận bị xử phạt đối với việc sử dụng UIDocument không phải là luồng an toàn? – Stuart

Trả lời

6

Nếu bạn đang gọi bất kỳ phương thức nào trong số các phương pháp writeContents:..., bạn không nên. Bạn nên gọi số saveToURL:forSaveOperation:completionHandler: để thay thế. Phương thức writeContents:... có nghĩa là cho phân lớp nâng cao.

UIDocument sử dụng hai luồng - chuỗi chính và chuỗi "Truy cập tệp UIDocument" (trong đó, nếu bạn phân lớp nhiều hơn UIDocument, bạn có thể thực hiện mọi thứ qua).

An toàn chủ đề với UIDocument giống như bất kỳ điều gì trong Mục tiêu C - chỉ cho phép chủ sở hữu đối tượng sửa đổi nó. Nếu đối tượng bạn muốn thay đổi đang được đọc, hãy xếp hàng đối tượng đó sau khi quá trình ghi hoàn tất. Có thể thay đổi một đối tượng khác thuộc sở hữu của lớp con UIDocument của bạn và kéo chúng vào một NSFileWrapper mới trong contentsForType:error:. Vượt qua một bản sao của tệpWrappers NSDictionary.

NSFileWrapper thực sự tải toàn bộ tài liệu vào bộ nhớ. NSFileWrapper thực sự được tạo trong chuỗi "Truy cập tệp UIDocument" theo phương pháp readFromURL:error:, sau đó được chuyển đến phương thức loadFromContents:ofType:error:. Nếu bạn có một tài liệu lớn, điều này có thể mất một lúc.

Khi lưu bạn thường muốn để UIDocument quyết định thời điểm thực hiện việc này và cho nó biết điều gì đó đã thay đổi thông qua phương thức updateChangeCount: (thông số là UIDocumentChangeDone). Khi bạn muốn lưu một cái gì đó ngay bây giờ bạn muốn sử dụng phương thức saveToURL:forSaveOperation:completionHandler:.

Một điều khác cần lưu ý là UIDocument triển khai giao thức NSFilePresenter, xác định phương thức cho NSFileCoordinator để sử dụng. UIDocument chỉ tọa độ viết trên tài liệu gốc chứ không phải các tệp phụ.Bạn có thể nghĩ rằng việc phối hợp các tệp phụ bên trong tài liệu có thể hữu ích, nhưng sự cố mà bạn nhận được có liên quan đến việc biến đổi từ điển trong khi nó đang được lặp lại, vì vậy sẽ không giúp được gì. Bạn chỉ cần lo lắng về việc viết NSFilePresenter của riêng mình nếu bạn (1) muốn nhận thông báo về thay đổi tệp hoặc (2) một đối tượng hoặc ứng dụng khác đang đọc/ghi vào cùng một tệp. Những gì UIDocument đã làm sẽ hoạt động tốt. Tuy nhiên, bạn muốn sử dụng NSFileCoordinator khi di chuyển/xóa toàn bộ tài liệu.

+0

Cảm ơn bạn đã trả lời. Tôi đã hiểu hầu hết những gì bạn đã đề cập (nhưng thật tuyệt khi được nêu rõ ở đây), ví dụ: Tôi đang ghi đè 'writeContents: ...' và gọi triển khai siêu thực của nó để thực hiện lưu trữ xem trước và tôi đang sử dụng 'updateChangeCount:' để gắn cờ yêu cầu lưu. Tôi cũng biết rằng 'UIDocument' xử lý sự phối hợp tập tin, tuy nhiên không phối hợp viết trên wrapper file gốc ngụ ý phối hợp trên các subfiles? Từ Hướng dẫn lập trình hệ thống tập tin: "Lưu ý: Khi một cá thể' NSFileWrapper' được chỉ định làm mục để phối hợp, tất cả các tệp ... – Stuart

+0

... trong trình bao bọc tệp tự động là một phần của sự phối hợp tệp đó. ". Tôi hiện đang sử dụng một đối tượng dữ liệu riêng biệt để lưu trữ dữ liệu (trong các trường 'Trang' thuộc lớp con' UIDocument' của tôi), nhưng ngay sau khi thay đổi được thực hiện, tôi đặt một trình bao bọc tệp mới trong trình bao bọc tệp gốc được thực hiện trong ứng dụng mẫu CloudNotes của Apple, thay vì đợi và thêm nó vào trong 'contentForType:'. Như bạn đã chỉ ra, đây chắc chắn là vấn đề. Tôi sẽ trì hoãn các bản cập nhật cho trình bao bọc tệp gốc cho đến khi 'UIDocument' yêu cầu ảnh chụp nhanh và xem liệu tất cả có hoạt động tốt hay không. Cảm ơn một lần nữa. – Stuart

+0

Tài liệu gây nhầm lẫn và tôi gặp vấn đề như bạn đã làm. Vì vậy, tôi figured tôi sẽ bao gồm càng nhiều càng tốt. Bạn có thể muốn lưu bản xem trước ở một nơi khác. CloudNotes thực hiện một số công cụ kỳ quặc - nó lưu một UIDocument thứ hai để xem trước. Bạn thực sự chỉ cần làm điều đó nếu bạn không phải lúc nào cũng giữ bản sao cục bộ của từng tài liệu. Có, nếu bạn phối hợp tài liệu gốc nó có thể áp dụng cho các tệp phụ, nhưng, theo như tôi biết, điều đó giả định ứng dụng/đối tượng khác phối hợp tài liệu gốc (iCloud & UIDocument thực hiện điều này). – Luke

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