2012-11-02 40 views
9

Chúng tôi đang làm việc trên một ứng dụng cấp doanh nghiệp, sẽ lưu trữ hàng chục nghìn đối tượng với dữ liệu lõi và chúng tôi đang gặp sự cố ở một số mặt trận.Đề xuất thiết kế bối cảnh đối tượng được quản lý dữ liệu lõi


Ứng dụng của chúng tôi có một số hệ thống độc lập hoạt động trên dữ liệu khi cần. Các hệ thống này bao gồm khám phá các mục, tải các mục, đồng bộ hóa và hiển thị giao diện người dùng. Nếu chúng tôi thiết kế phần mềm của chúng tôi một cách chính xác, sẽ có ít hoặc không có xung đột hợp nhất do các hệ thống khác nhau sửa đổi cùng một đối tượng. Mỗi hệ thống có hàng đợi hoạt động riêng, tất cả đều hoạt động trong nền. Chúng tôi muốn giữ tất cả các đối tượng tạo và sửa đổi trong nền để giảm thiểu các vấn đề hiệu suất UI, đặc biệt là trong đoạn đường nối ban đầu, nơi hàng nghìn đối tượng có thể được tạo từ dữ liệu trên máy chủ. Ở đây chúng tôi đã gặp phải một số vấn đề với các nỗ lực thiết kế khác nhau của chúng tôi. Mức tiêu thụ bộ nhớ lớn trong những lần tăng tốc này, và sự phối hợp không chính xác của tất cả các bối cảnh và ngữ cảnh của trẻ em, gây ra các sự cố và sự cố. Chúng tôi đã cố gắng thiết kế dưới đây:

  • Một gốc NSPrivateQueueConcurrencyType quản lý bối cảnh đối tượng trong đó có một trẻ em NSMainQueueConcurrencyType ngữ cảnh. Bộ điều khiển kết quả tìm nạp được giao diện người dùng sử dụng ngữ cảnh con này để tìm nạp kết quả từ đó. Từ ngữ cảnh trẻ em NSMainQueueConcurrencyType, chúng tôi đã tạo một ngữ cảnh con NSPrivateQueueConcurrencyType, chúng tôi gọi là "savingContext" và mỗi thao tác nền tạo ra ngữ cảnh con của "savingContext" đó, đã thực hiện các thay đổi và cuối cùng là tiết kiệm đến đỉnh. Ban đầu, chúng tôi đã chọn thiết kế này để không phải xử lý các thông báo NSManagedObjectContextDidSaveNotification từ nhiều ngữ cảnh con khác nhau. Chúng tôi gói mọi cuộc gọi đến các ngữ cảnh NSPrivateQueueConcurrencyType và truy cập vào các đối tượng với performBlockAndWait:. Chức năng, thiết kế này được thực hiện. Tất cả các thay đổi và chèn đã được lưu vào cửa hàng liên tục và giao diện người dùng đã được cập nhật với các thay đổi. Điều này, đã giới thiệu hai vấn đề. Một trong số đó là giao diện người dùng bị chậm trễ trong đoạn đường nối vì các thay đổi đã hợp nhất đi qua ngữ cảnh của trẻ em NSMainQueueConcurrencyType và quan trọng hơn là sử dụng bộ nhớ rất cao trong khi tăng tốc. Chúng tôi sẽ nhấn vào việc sử dụng RAM cấm do không có khả năng gọi reset đệ quy theo ngữ cảnh (vì ngữ cảnh giao diện người dùng chính cũng có) và/hoặc thiếu kiến ​​thức khi gọi refreshObject:mergeChanges:. Vì vậy, chúng tôi đã đi một con đường khác.
  • Có hai ngữ cảnh cấp cao nhất được liên kết với điều phối viên cửa hàng liên tục, một NSPrivateQueueConcurrencyType để lưu ngữ cảnh con và hiển thị NSMainQueueConcurrencyType cho giao diện người dùng. NSMainQueueConcurrencyType nghe các thông báo NSManagedObjectContextDidSaveNotification từ ngữ cảnh NSPrivateQueueConcurrencyType chính và hợp nhất chúng trong chuỗi chính. Mỗi thao tác nền tạo ra bối cảnh con của bối cảnh NSPrivateQueueConcurrencyType chính, cũng với kiểu đồng thời hàng đợi riêng, thực hiện những gì nó thực hiện, thực hiện "lưu sâu" đệ quy, thực hiện lưu trên ngữ cảnh hiện tại, một cuộc gọi đệ quy để lưu sâu vào cha mẹ, cuộc gọi được đặt lại trên ngữ cảnh hiện tại và lưu lại. Bằng cách này, chúng tôi tránh các vấn đề về bộ nhớ, vì các đối tượng đã tạo được phát hành nhanh chóng sau khi lưu. Tuy nhiên, với thiết kế này, chúng tôi đã gặp rất nhiều vấn đề như khóa chết, NSInternalInconsistencyException ngoại lệ và bộ kiểm soát kết quả được tải xuống không cập nhật giao diện người dùng mặc dù có lưu thông báo cho ngữ cảnh NSMainQueueConcurrencyType. Điều này cũng gây ra thời gian tải ban đầu trong giao diện người dùng để làm chậm rất nhiều. Trong thiết kế trước đó, bộ điều khiển kết quả tìm nạp trả về kết quả rất nhanh, trong khi điều này có giao diện người dùng bị chặn trong vài giây cho đến khi khung nhìn tải (chúng tôi khởi tạo bộ điều khiển kết quả được tìm nạp trong viewDidLoad).

Chúng tôi đã thử nhiều thiết kế trung gian, nhưng chúng xoay quanh cùng một vấn đề, sử dụng bộ nhớ rất cao, bộ điều khiển kết quả tìm nạp không cập nhật giao diện người dùng hoặc deadlocks và NSInternalInconsistencyException ngoại lệ.


Tôi thực sự cảm thấy thất vọng. Tôi không thể nhưng cảm thấy như thể thiết kế của chúng ta quá phức tạp đối với một thứ gì đó khá đơn giản, và nó chỉ là sự thiếu hiểu biết của chúng ta về một số cơ bản đang giết chết chúng ta.


Vì vậy, các bạn sẽ đề xuất điều gì? Bạn sẽ đề xuất sự sắp xếp nào cho bối cảnh của chúng tôi? Làm thế nào chúng ta nên quản lý các bối cảnh khác nhau trong các chủ đề khác nhau? Các phương pháp hay nhất để giải phóng các đối tượng được chèn và đặt lại bối cảnh? Tránh khóa chết? Tất cả sự giúp đỡ sẽ được đánh giá cao vào thời điểm này.


Tôi cũng đã xem các đề xuất cho danh mục MagicalRecords. Được khuyến nghị? Chúng tôi đã đầu tư vào việc sử dụng các loại Dữ liệu cốt lõi, sẽ khó khăn như thế nào khi di chuyển bằng MR?

+0

Tôi gặp sự cố tương tự (kiến trúc một): http://stackoverflow.com/questions/15999932/core-data-break-retain-cycle-of-the-parent-context/16008470 - Loại kiến ​​trúc nào cuối cùng bạn có đi không? Có lời khuyên nào không? – Zyphrax

+0

Chúng tôi có ngữ cảnh chính và bối cảnh gốc của bố mẹ. Nhưng bối cảnh gốc chỉ được sử dụng để tiết kiệm, vì vậy chúng tôi thiết lập lại nó trên mọi lưu. Chúng tôi có vô số vấn đề. Có vẻ như những tính năng mới này của bối cảnh con và cha mẹ không được suy nghĩ tốt và có rất nhiều lỗi vẫn chưa được Apple giám sát. –

+0

Tôi đang hướng tới kiến ​​trúc với một MOC gốc (PrivateQueue) với một MOC con (MainQueue) và giảm bộ nhớ bằng cách thêm '' '[self.managedObjectContext refreshObject: self mergeChanges: NO];' '' call in '' '-didSave''' trong một số ManagedObject của tôi. Điều này phá vỡ chu kỳ giữ lại giữa các mối quan hệ và cho phép tất cả các MOC để deallocate các đối tượng. Chỉ những MOC với NSPrivateQueueConcurrencyType dường như có một vấn đề kỳ lạ là chúng sẽ không giải quyết các đối tượng ngay lập tức mà vào lần lưu/khôi phục tiếp theo. – Zyphrax

Trả lời

6

Trước tiên, để quản lý bộ nhớ của bạn, kiến ​​trúc thứ hai của bạn mang đến cho bạn sự linh hoạt hơn nhiều.

Thứ hai, có hai loại bộ nhớ để quản lý: bộ nhớ malloc-ed và bộ nhớ VM thường trú. Bạn có thể có dấu chân bộ nhớ malloc-ed thấp và vẫn có một khu vực máy ảo lớn. Điều này là do, theo kinh nghiệm của tôi, để Core dữ liệu tích cực giữ cho các mục mới được chèn vào. Tôi giải quyết vấn đề này với thông báo cắt xén sau khi lưu.

Thứ ba, MOC rẻ. Sử dụng và ném đi. Nói cách khác, phát hành bộ nhớ sớm và thường xuyên.

Thứ tư, cố gắng làm hầu như không có dữ liệu nào dựa trên dữ liệu chính trên MOC chính. Vâng, điều này nghe có vẻ ngược lại. Ý tôi là tất cả các truy vấn phức tạp của bạn thực sự nên được thực hiện trên các chủ đề nền và sau đó có các kết quả được chuyển đến luồng chính hoặc có các truy vấn được làm lại từ luồng chính trong khi khai thác hàng-cache hiện tại. Bằng cách này, bạn giữ giao diện người dùng trực tiếp.

Thứ năm, trong ứng dụng nhiều hàng đợi của tôi, tôi cố gắng để có tất cả các lưu của tôi thực sự xảy ra trong nền. Điều này giúp MOC chính của tôi nhanh chóng và nhất quán với dữ liệu đến từ mạng.

Thứ sáu, NSFetchedResultsController là một bộ điều khiển khá hữu dụng nhưng chuyên dụng. Nếu ứng dụng của bạn đẩy nó ra ngoài phạm vi thẩm quyền của nó, nó sẽ bắt đầu khóa giao diện của bạn. Khi điều đó xảy ra, tôi cuộn bộ điều khiển của chính mình bằng cách lắng nghe bản thân thông báo -didSave.

+0

Cảm ơn câu trả lời của bạn! Điều gì về khóa up? Hiện tại, ứng dụng của chúng tôi bị khóa theo thời gian, vì những lý do không rõ ràng với chúng tôi. Nó thường bị khóa khi gọi 'mergeChangesFromContextDidSaveNotification:' sau một thông báo. Một số luồng có thể lưu cùng một lúc không? Ngữ cảnh có bị khóa không? –

+0

Leo, tôi giảm thiểu thời gian giao diện người dùng của tôi bị khóa trong MOC chính bằng cách cố gắng không bao giờ lưu bất kỳ thay đổi nào từ nó. I E. dữ liệu mới nhập vào từ nền. Điều đó giữ MOC chính miễn phí. Ngoài ra, kiểm tra xem liệu khóa có phải là do bạn đang cập nhật trình điều khiển kết quả đã tìm nạp của mình hay chỉ cần hợp nhất các MOC. (Tôi đang cá cược trước đây. Bạn có thể kiểm tra bằng cách không thiết lập các đại biểu FRC.) Có, một số chủ đề có thể tiết kiệm cùng một lúc. Vì SQLite là một kho lưu trữ luồng đơn, mọi thứ được tuần tự hóa thông qua PSC - cũng đọc. Kết quả là, tôi tuần tự hóa việc ghi/lưu thông qua MOC nền của tôi. Andrew – adonoho

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