Ví dụ hoặc giải thích về Di chuyển dữ liệu cốt lõi với nhiều lần vượt qua?


85

Ứng dụng iPhone của tôi cần phải di chuyển kho dữ liệu cốt lõi và một số cơ sở dữ liệu khá lớn. Tài liệu của Apple đề xuất sử dụng "nhiều lần" để di chuyển dữ liệu nhằm giảm việc sử dụng bộ nhớ. Tuy nhiên, tài liệu rất hạn chế và không giải thích rõ cách thực hiện việc này. Ai đó có thể chỉ cho tôi một ví dụ điển hình hoặc giải thích chi tiết quá trình làm thế nào để thực sự rút ra được điều này không?


Bạn đã thực sự gặp sự cố bộ nhớ? Việc di chuyển của bạn có trọng lượng nhẹ hay muốn sử dụng NSMigrationManager?
Nick Weaver

Có, bảng điều khiển GDB cho thấy đã có cảnh báo về bộ nhớ và sau đó ứng dụng bị treo do bộ nhớ hạn chế. Tôi đã thử cả di chuyển nhẹ và NSMigrationManager, nhưng ngay bây giờ tôi đang cố gắng sử dụng NSMigrationManager.
Jason

được rồi, bạn có thể đi chi tiết hơn một chút về những gì đã thay đổi không?
Nick Weaver

cuối cùng, tôi đã tìm ra, đọc câu trả lời của tôi.
Nick Weaver

Xin chào Jason, bạn có thể sửa lỗi tương tự trong câu hỏi không?
Yuchen Zhong

Câu trả lời:


174

Tôi đã tìm ra những gì Apple gợi ý trong tài liệu của họ . Nó thực sự rất dễ dàng nhưng một chặng đường dài trước khi nó trở nên rõ ràng. Tôi sẽ minh họa lời giải thích bằng một ví dụ. Tình huống ban đầu là:

Phiên bản mô hình dữ liệu 1

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Đây là mô hình bạn nhận được khi tạo dự án với mẫu "ứng dụng điều hướng có lưu trữ dữ liệu cốt lõi". Tôi đã biên dịch nó và thực hiện một số thao tác khó với sự trợ giúp của vòng lặp for để tạo khoảng 2k mục nhập với một số giá trị khác nhau. Chúng ta có 2.000 sự kiện với giá trị NSDate.

Bây giờ chúng tôi thêm phiên bản thứ hai của mô hình dữ liệu, trông giống như sau:

nhập mô tả hình ảnh ở đây

Phiên bản mô hình dữ liệu 2

Sự khác biệt là: Thực thể Sự kiện đã biến mất và chúng tôi có hai thực thể mới. Một cái lưu trữ một dấu thời gian dưới dạng một doublevà cái thứ hai sẽ lưu trữ một ngày tháng dưới dạng NSString.

Mục tiêu là chuyển tất cả Sự kiện phiên bản 1 sang hai thực thể mới và chuyển đổi các giá trị trong quá trình di chuyển. Điều này dẫn đến hai lần các giá trị, mỗi giá trị là một kiểu khác nhau trong một thực thể riêng biệt.

Để di chuyển, chúng tôi chọn di chuyển bằng tay và điều này chúng tôi thực hiện với các mô hình bản đồ. Đây cũng là phần đầu tiên của câu trả lời cho câu hỏi của bạn. Chúng tôi sẽ thực hiện di chuyển trong hai bước, vì mất nhiều thời gian để di chuyển 2k mục nhập và chúng tôi muốn giữ cho bộ nhớ thấp.

Bạn thậm chí có thể tiếp tục và chia nhỏ các mô hình ánh xạ này để chỉ di chuyển các phạm vi thực thể. Giả sử chúng tôi có một triệu bản ghi, điều này có thể làm hỏng toàn bộ quá trình. Có thể thu hẹp các thực thể được tải xuống bằng một vị từ Bộ lọc .

Quay lại hai mô hình ánh xạ của chúng tôi.

Chúng tôi tạo mô hình ánh xạ đầu tiên như sau:

1. Tệp mới -> Tài nguyên -> Mô hình ánh xạ nhập mô tả hình ảnh ở đây

2. Chọn tên, tôi đã chọn StepOne

3. Đặt mô hình dữ liệu nguồn và đích

nhập mô tả hình ảnh ở đây

Mô hình lập bản đồ Bước một

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Di chuyển nhiều lần không cần chính sách di chuyển thực thể tùy chỉnh, tuy nhiên, chúng tôi sẽ thực hiện điều đó để có thêm một chút chi tiết cho ví dụ này. Vì vậy, chúng tôi thêm một chính sách tùy chỉnh vào thực thể. Đây luôn là một lớp con của NSEntityMigrationPolicy.

nhập mô tả hình ảnh ở đây

Lớp chính sách này thực hiện một số phương thức để làm cho quá trình di chuyển của chúng ta diễn ra. Tuy nhiên nó đơn giản trong trường hợp này vì vậy chúng tôi sẽ phải thực hiện phương pháp duy nhất: createDestinationInstancesForSourceInstance:entityMapping:manager:error:.

Việc triển khai sẽ như thế này:

StepOneEntityMigrationPolicy.m

#import "StepOneEntityMigrationPolicy.h"


@implementation StepOneEntityMigrationPolicy

- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance 
                                      entityMapping:(NSEntityMapping *)mapping 
                                            manager:(NSMigrationManager *)manager 
                                              error:(NSError **)error
{
    // Create a new object for the model context
    NSManagedObject *newObject = 
        [NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName] 
                                      inManagedObjectContext:[manager destinationContext]];

    // do our transfer of nsdate to nsstring
    NSDate *date = [sInstance valueForKey:@"timeStamp"];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];    

    // set the value for our new object
    [newObject setValue:[dateFormatter stringFromDate:date] forKey:@"printedDate"];
    [dateFormatter release];

    // do the coupling of old and new
    [manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];

    return YES;
}

Bước cuối cùng: chính quá trình di chuyển

Tôi sẽ bỏ qua phần thiết lập mô hình ánh xạ thứ hai gần như giống hệt nhau, chỉ là timeIntervalSince1970 được sử dụng để chuyển đổi NSDate thành double.

Cuối cùng, chúng ta cần kích hoạt quá trình di chuyển. Bây giờ tôi sẽ bỏ qua đoạn mã soạn sẵn. Nếu bạn cần, tôi sẽ đăng ở đây. Nó có thể được tìm thấy tại Customizing the Migration Process, nó chỉ là sự hợp nhất của hai ví dụ mã đầu tiên. Phần thứ ba và phần cuối cùng sẽ được sửa đổi như sau: Thay vì sử dụng phương thức lớp của NSMappingModellớp, mappingModelFromBundles:forSourceModel:destinationModel:chúng ta sẽ sử dụng initWithContentsOfURL:phương thức bởi vì phương thức lớp sẽ chỉ trả về một, có thể là mô hình ánh xạ đầu tiên, được tìm thấy trong gói.

Bây giờ chúng ta đã có hai mô hình ánh xạ có thể được sử dụng trong mỗi lần vượt qua vòng lặp và gửi phương thức di chuyển đến trình quản lý di chuyển. Đó là nó.

NSArray *mappingModelNames = [NSArray arrayWithObjects:@"StepOne", @"StepTwo", nil];
NSDictionary *sourceStoreOptions = nil;

NSURL *destinationStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMigrationNew.sqlite"];

NSString *destinationStoreType = NSSQLiteStoreType;

NSDictionary *destinationStoreOptions = nil;

for (NSString *mappingModelName in mappingModelNames) {
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:mappingModelName withExtension:@"cdm"];

    NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];

    BOOL ok = [migrationManager migrateStoreFromURL:sourceStoreURL
                                               type:sourceStoreType
                                            options:sourceStoreOptions
                                   withMappingModel:mappingModel
                                   toDestinationURL:destinationStoreURL
                                    destinationType:destinationStoreType
                                 destinationOptions:destinationStoreOptions
                                              error:&error2];
    [mappingModel release];
} 

Ghi chú

  • Một mô hình ánh xạ kết thúc trong cdmgói.

  • Cửa hàng đích phải được cung cấp và không được là cửa hàng nguồn. Bạn có thể sau khi di chuyển thành công xóa cái cũ và đổi tên cái mới.

  • Tôi đã thực hiện một số thay đổi đối với mô hình dữ liệu sau khi tạo các mô hình ánh xạ, điều này dẫn đến một số lỗi tương thích mà tôi chỉ có thể giải quyết bằng cách tạo lại các mô hình ánh xạ.


59
Địa ngục đẫm máu thật phức tạp. Apple đang nghĩ gì?
aroth

7
Tôi không biết, nhưng bất cứ khi nào tôi nghĩ rằng dữ liệu cốt lõi là một ý tưởng hay, tôi sẽ cố gắng tìm ra một giải pháp đơn giản và dễ bảo trì hơn.
Nick Weaver

5
Cảm ơn! Đây là một câu trả lời tuyệt vời. Nó có vẻ phức tạp, nhưng nó không phải là xấu khi bạn học các bước. Vấn đề lớn nhất là tài liệu không giải thích nó cho bạn như thế này.
bentford

2
Đây là liên kết được cập nhật để Tùy chỉnh Quy trình Di chuyển. Nó đã di chuyển kể từ khi bài đăng này được viết. developer.apple.com/library/ios/documentation/Cocoa/Conceptual/...
user1021430

@NickWeaver, bạn xác định đích đến như thế nào? Bạn đang tạo nó hay nó được tạo ra bởi hệ thống dữ liệu cốt lõi trong quá trình di chuyển ????
dev gr

3

Những câu hỏi này có liên quan:

Sự cố bộ nhớ khi di chuyển kho dữ liệu CoreData lớn trên iPhone

Di chuyển dữ liệu cốt lõi nhiều lần trong từng đoạn với iOS

Để trích dẫn liên kết đầu tiên:

Điều này được thảo luận trong tài liệu chính thức trong phần "Nhiều thẻ", tuy nhiên, có vẻ như cách tiếp cận được đề xuất của họ là phân chia quá trình di chuyển của bạn theo loại thực thể, tức là tạo nhiều mô hình ánh xạ, mỗi mô hình sẽ di chuyển một tập hợp con của các loại thực thể từ hoàn thiện mô hình dữ liệu.


1
Cảm ơn vì các liên kết. Vấn đề là không ai thực sự giải thích chi tiết cách thiết lập nó trong nhiều lần vượt qua. Tôi nên thiết lập nhiều mô hình ánh xạ như thế nào để nó hoạt động hiệu quả?
Jason

-5

Giả sử lược đồ cơ sở dữ liệu của bạn có 5 thực thể, ví dụ: người, sinh viên, khóa học, lớp và đăng ký để sử dụng loại ví dụ tiêu chuẩn, trong đó các lớp con của sinh viên, lớp triển khai khóa học và đăng ký tham gia lớp và sinh viên. Nếu bạn đã thực hiện các thay đổi đối với tất cả các định nghĩa bảng này, bạn phải bắt đầu ở các lớp cơ sở và làm việc theo cách của bạn. Vì vậy, bạn không thể bắt đầu với việc chuyển đổi đăng ký, vì mỗi hồ sơ đăng ký phụ thuộc vào việc có lớp học và sinh viên ở đó. Vì vậy, bạn sẽ bắt đầu với việc chỉ di chuyển bảng Person, sao chép các hàng hiện có vào bảng mới và điền vào bất kỳ trường mới nào ở đó (nếu có thể) và loại bỏ các cột đã loại bỏ. Thực hiện mỗi lần di chuyển bên trong một nhóm tự động khôi phục để sau khi hoàn tất, bộ nhớ của bạn sẽ bắt đầu trở lại.

Sau khi hoàn thành xong bảng Person, bạn có thể chuyển đổi bảng sinh viên. Sau đó chuyển đến Khóa học rồi đến Lớp học và cuối cùng là bảng Đăng ký.

Cân nhắc khác là số lượng bản ghi, nếu giống như Person có một nghìn hàng, bạn sẽ phải, cứ mỗi 100 hoặc lâu hơn, thực thi NSManagedObject tương đương với một bản phát hành, nghĩa là cho biết ngữ cảnh đối tượng được quản lý [moc refreshObject: ob mergeChanges: KHÔNG]; Đồng thời đặt bộ hẹn giờ dữ liệu cũ của bạn ở mức thấp để bộ nhớ thường xuyên bị xóa.


Vì vậy, về cơ bản bạn đề xuất có một lược đồ dữ liệu cốt lõi mới mà không phải là một phần của lược đồ cũ và sao chép dữ liệu vào lược đồ mới bằng tay?
Jason

-1 Ánh xạ thủ công cơ sở dữ liệu của bạn là không cần thiết. Bạn có thể di chuyển cơ sở dữ liệu đã triển khai bằng cách sử dụng di chuyển nhẹ hoặc với MappingModels rõ ràng.
bentford
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.