Tôi đã có một doozey của một vấn đề mà tôi đã làm việc trên một vài tuần. Nó liên quan đến hiệu suất giao diện người dùng nói lắp bất cứ khi nào tôi lưu bối cảnh đối tượng được quản lý dữ liệu lõi của mình. Tôi đã nhận được như xa như tôi có thể một mình và đang tìm kiếm một số trợ giúp.Bối cảnh được quản lý đối tượng bối cảnh Staggers UI Animation
Tình huống
Ứng dụng của tôi sử dụng hai trường hợp NSManagedObjectContext
. Một thuộc về đại biểu ứng dụng và có một điều phối viên lưu trữ liên tục gắn liền với nó. Cái còn lại là con của MOC chính và thuộc về một đối tượng Class
, được gọi là PhotoFetcher
. Nó sử dụng NSPrivateQueueConcurrencyType
vì vậy tất cả các hoạt động thực hiện trên MOC này diễn ra trong một hàng đợi nền.
Ứng dụng của chúng tôi tải xuống dữ liệu JSON biểu thị dữ liệu về ảnh từ API của chúng tôi. Để lấy dữ liệu từ API của chúng tôi, trình tự các bước như sau xảy ra:
- Xây dựng một đối tượng
NSURLRequest
và sử dụng giao thứcNSURLConnectionDataDelegate
để xây dựng dữ liệu trả về từ yêu cầu, hoặc xử lý lỗi. - Sau khi tải về các dữ liệu JSON là hoàn chỉnh, thực hiện một khối trên hàng đợi MOC thứ của nào sau đây:
- Phân tích các JSON sử dụng
NSJSONSerialization
vào trường lớp Foundation. - Lặp lại dữ liệu được phân tích cú pháp, chèn hoặc cập nhật các đối tượng trong ngữ cảnh nền khi cần. Thông thường, điều này dẫn đến khoảng 300 thực thể mới hoặc được cập nhật.
- Lưu ngữ cảnh nền. Điều này lan truyền các thay đổi của tôi cho MOC chính.
- Thực hiện một khối trên MOC chính để lưu đó là ngữ cảnh. Điều này là để dữ liệu của chúng tôi được lưu vào đĩa, một cửa hàng
SQLite
. Cuối cùng, gọi lại cho một đại biểu thông báo cho họ biết rằng phản hồi đã được chèn hoàn toàn vào kho dữ liệu lõi.
- Phân tích các JSON sử dụng
Mã để lưu MOC nền trông giống như sau:
[AppDelegate.managedObjectContext performBlock:^{
[AppDelegate saveContext]; //A standard save: call to the main MOC
}];
Khi bối cảnh đối tượng chính tiết kiệm, nó cũng tiết kiệm một số hợp lý của ảnh JPEG đã được tải về từ cuối cùng thời gian một bối cảnh đối tượng chính lưu xảy ra. Hiện tại, trên iPhone 4, chúng tôi đang tải xuống 15 hình ảnh 200x200 JPEG ở mức nén 70% hoặc tổng cộng khoảng 2MB dữ liệu.
Sự cố
Tính năng này hoạt động và hoạt động tốt. Vấn đề của tôi là khi bối cảnh nền tiết kiệm, NSFetchedResultsController
đang chạy trong trình điều khiển chế độ xem của tôi chọn các thay đổi được truyền đến MOC chính. Nó chèn các ô mới vào số PSTCollectionView
, một bản sao mã nguồn mở của UICollectionView
. Trong khi nó chèn các ô mới, bối cảnh chính lưu và ghi những thay đổi đó vào đĩa. Điều này có thể thực hiện, trên iPhone 4 chạy iOS 5.1, ở bất kỳ đâu từ 250-350ms.
Trong thời gian đó thứ ba của một giây, ứng dụng hoàn toàn không phản hồi. Ảnh động đang diễn ra trước khi lưu được tạm dừng và không có sự kiện người dùng mới nào được gửi đến vòng lặp chạy chính cho đến khi quá trình lưu hoàn tất.
Tôi đã chạy ứng dụng của mình trong Công cụ bằng Trình tạo thời gian để xác định nội dung nào đang chặn chuỗi chính của chúng tôi. Thật không may, kết quả đã được khá mờ đục. Đây là dấu vết ngăn xếp nặng nhất mà tôi nhận được từ Dụng cụ.
Nó xuất hiện để được tiết kiệm thông tin cập nhật đến cửa hàng dai dẳng, nhưng tôi không thể chắc chắn. Vì vậy, tôi đã xóa mọi cuộc gọi đến saveContext
vì vậy MOC sẽ không chạm vào đĩa và cuộc gọi chặn trên chủ đề chính vẫn còn tồn tại.
Các dấu vết, dưới dạng văn bản, trông như thế này:
Symbol Name
-[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
-[NSManagedObjectContext executeFetchRequest:error:]
-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]
_perform
_dispatch_barrier_sync_f_invoke
_dispatch_client_callout
__82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0
-[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
-[NSManagedObjectContext executeFetchRequest:error:]
-[NSPersistentStoreCoordinator executeRequest:withContext:error:]
-[NSSQLCore executeRequest:withContext:error:]
-[NSSQLCore objectsForFetchRequest:inContext:]
-[NSSQLCore newRowsForFetchPlan:]
-[NSSQLCore _newRowsForFetchPlan:selectedBy:withArgument:]
-[NSSQLiteConnection execute]
gì tôi đã cố gắng
Trước khi chúng tôi chạm vào mã Core Data, điều đầu tiên chúng tôi làm là tối ưu hóa hình ảnh JPEG của chúng tôi. Chúng tôi đã chuyển sang các hình JPEG nhỏ hơn và thấy hiệu suất tăng lên. Sau đó, chúng tôi đã giảm số lượng ảnh JPEG mà chúng tôi tải xuống tại một thời điểm (từ 90 xuống còn 15). Điều này cũng dẫn đến tăng hiệu suất đáng kể. Tuy nhiên, chúng ta vẫn thấy các khối dài 250-350ms trên sợi chính.
Điều đầu tiên tôi đã thử chỉ là loại bỏ MOC nền để loại bỏ khả năng có thể gây ra sự cố. Trong thực tế, nó làm mọi thứ tồi tệ hơn vì mã cập nhật hoặc tạo của chúng tôi đang chạy trên luồng chính và làm cho hiệu suất hoạt ảnh tổng thể bị suy giảm.
Thay đổi cửa hàng liên tục thành NSInMemoryStoreType
không có hiệu lực.
Mọi người có thể chỉ cho tôi "bí mật" sẽ cho tôi hiệu suất giao diện người dùng mà bối cảnh đối tượng được quản lý nền đã hứa không?
Dường như đối tượng bạn đang lưu đang bị lỗi trên chuỗi chính. Bạn có thể chạy trình thu thập dữ liệu lõi để xem nguyên nhân gây ra lỗi không? Và bạn có sử dụng các mối quan hệ nghịch đảo không? – ndfred
Tôi sẽ thanh toán bộ kiểm tra CD, nhưng tôi sử dụng mối quan hệ inver. –