Advertisement
  1. Code
  2. Core Data

iOS 8: Core Data dan Pengambilan Asinkron

Scroll to top
Read Time: 14 min
This post is part of a series called Core Data from Scratch.
iOS 8: Core Data and Batch Updates

Indonesian (Bahasa Indonesia) translation by Yudha Zubair (you can also view the original English article)

Pada artikel sebelumnya tentang iOS 8 dan Core Data, kami membahas pembaruan batch. Pembaruan Batch bukan satu-satunya API baru di kota. Pada iOS 8 dan OS X Yosemite, dimungkinkan untuk mengambil data secara asinkron. Dalam tutorial ini, kita akan melihat lebih dekat bagaimana menerapkan pengambilan asinkron dan dalam situasi apa aplikasi Anda dapat mengambil manfaat dari API baru ini.

1. Masalah

Seperti pembaruan batch, pengambilan asinkron telah ada dalam daftar keinginan banyak pengembang selama beberapa waktu. Mengambil permintaan bisa jadi rumit, membutuhkan waktu yang tidak sepele untuk diselesaikan. Selama waktu itu, permintaan pengambilan memblokir thread yang sedang berjalan dan, sebagai hasilnya, memblokir akses ke konteks objek yang dikelola yang mengeksekusi permintaan pengambilan. Masalahnya sederhana untuk dipahami, tetapi seperti apa solusi Apple.

2. Solusinya

Jawaban Apple untuk masalah ini adalah pengambilan asinkron. Permintaan pengambilan asinkron berjalan di latar belakang. Ini berarti bahwa itu tidak memblokir tugas-tugas lain saat sedang dieksekusi, seperti memperbarui antarmuka pengguna pada thread utama.

Pengambilan asinkron juga menampilkan dua fitur nyaman lainnya, pelaporan kemajuan dan pembatalan. Permintaan pengambilan asinkron dapat dibatalkan kapan saja, misalnya, ketika pengguna memutuskan permintaan pengambilan terlalu lama untuk diselesaikan. Pelaporan kemajuan adalah tambahan yang berguna untuk menunjukkan kepada pengguna kondisi permintaan pengambilan saat ini.

Pengambilan asinkron adalah API yang fleksibel. Tidak hanya memungkinkan untuk membatalkan permintaan pengambilan asinkron, tetapi juga memungkinkan untuk membuat perubahan pada konteks objek yang dikelola saat permintaan pengambilan asinkron dijalankan. Dengan kata lain, pengguna dapat terus menggunakan aplikasi Anda saat aplikasi mengeksekusi permintaan pengambilan asinkron di latar belakang.

3. Bagaimana Cara Kerjanya?

Seperti pembaruan batch, permintaan pengambilan asinkron diserahkan ke konteks objek terkelola sebagai objek NSPersistentStoreRequest, turunan dari kelas NSAsynchronousFetchRequest tepatnya.

Instance NSAsynchronousFetchRequest diinisialisasi dengan objek NSFetchRequest dan blok completion. Blok completion dijalankan ketika permintaan pengambilan asinkron telah menyelesaikan permintaan pengambilannya.

Mari kita kembali ke aplikasi to-do yang kita buat sebelumnya dalam seri ini dan menggantikan implementasi saat ini dari kelas NSFetchedResultsController dengan permintaan pengambilan asinkron.

Langkah 1: Pengaturan Proyek

Unduh atau klon proyek dari GitHub dan buka di Xcode 6. Sebelum kita dapat mulai bekerja dengan kelas NSAsynchronousFetchRequest, kita perlu membuat beberapa perubahan. Kami tidak akan dapat menggunakan kelas NSFetchedResultsController untuk mengelola data tampilan tabel karena kelas NSFetchedResultsController dirancang untuk berjalan di thread utama.

Langkah 2: Memasang Kembali Results Controller yang Diambil

Mulailah dengan memperbarui ekstensi kelas private dari kelas TSPViewController seperti yang ditunjukkan di bawah ini. Kami menghapus properti fetchedResultsController dan membuat properti baru, items, dari tipe NSArray untuk menyimpan item to-do. Ini juga berarti bahwa kelas TSPViewController tidak perlu lagi mematuhi protokol NSFetchedResultsControllerDelegate.

1
@interface TSPViewController ()
2
3
@property (strong, nonatomic) NSArray *items;
4
5
@property (strong, nonatomic) NSIndexPath *selection;
6
7
@end

Sebelum kita memperbaiki metode viewDidLoad, saya pertama-tama ingin memperbarui implementasi protokol UITableViewDataSource. Lihatlah perubahan yang saya buat di blok kode berikut.

1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
2
    return self.items ? 1 : 0;
3
}
1
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
2
    return self.items ? self.items.count : 0;
3
}
1
- (void)configureCell:(TSPToDoCell *)cell atIndexPath:(NSIndexPath *)indexPath {
2
    // Fetch Record

3
    NSManagedObject *record = [self.items objectAtIndex:indexPath.row];
4
    
5
    // Update Cell

6
    [cell.nameLabel setText:[record valueForKey:@"name"]];
7
    [cell.doneButton setSelected:[[record valueForKey:@"done"] boolValue]];
8
    
9
    [cell setDidTapButtonBlock:^{
10
        BOOL isDone = [[record valueForKey:@"done"] boolValue];
11
        
12
        // Update Record

13
        [record setValue:@(!isDone) forKey:@"done"];
14
    }];
15
}
1
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
2
    if (editingStyle == UITableViewCellEditingStyleDelete) {
3
        NSManagedObject *record = [self.items objectAtIndex:indexPath.row];
4
        
5
        if (record) {
6
            [self.managedObjectContext deleteObject:record];
7
        }
8
    }
9
}

Kita juga perlu mengubah satu baris kode dalam metode prepForSegue:sender: seperti yang ditunjukkan di bawah ini.

1
// Fetch Record

2
NSManagedObject *record = [self.items objectAtIndex:self.selection.row];

Terakhir tapi bukan yang akhir, hapus implementasi protokol NSFetchedResultsControllerDelegate karena kita tidak lagi membutuhkannya.

Langkah 3: Membuat Permintaan Ambil Asinkron

Seperti yang Anda lihat di bawah, kami membuat permintaan pengambilan asinkron dalam metode viewDidLoad view controller. Mari kita luangkan waktu untuk melihat apa yang terjadi.

1
- (void)viewDidLoad {
2
    [super viewDidLoad];
3
    
4
    // Helpers

5
    __weak TSPViewController *weakSelf = self;
6
    
7
    // Initialize Fetch Request

8
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"TSPItem"];
9
    
10
    // Add Sort Descriptors

11
    [fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:YES]]];
12
    
13
    // Initialize Asynchronous Fetch Request

14
    NSAsynchronousFetchRequest *asynchronousFetchRequest = [[NSAsynchronousFetchRequest alloc] initWithFetchRequest:fetchRequest completionBlock:^(NSAsynchronousFetchResult *result) {
15
        dispatch_async(dispatch_get_main_queue(), ^{
16
            // Process Asynchronous Fetch Result

17
            [weakSelf processAsynchronousFetchResult:result];
18
        });
19
    }];
20
    
21
    // Execute Asynchronous Fetch Request

22
    [self.managedObjectContext performBlock:^{
23
        // Execute Asynchronous Fetch Request

24
        NSError *asynchronousFetchRequestError = nil;
25
        NSAsynchronousFetchResult *asynchronousFetchResult = (NSAsynchronousFetchResult *)[weakSelf.managedObjectContext executeRequest:asynchronousFetchRequest error:&asynchronousFetchRequestError];
26
        
27
        if (asynchronousFetchRequestError) {
28
            NSLog(@"Unable to execute asynchronous fetch result.");
29
            NSLog(@"%@, %@", asynchronousFetchRequestError, asynchronousFetchRequestError.localizedDescription);
30
        }
31
    }];
32
}

Kami mulai dengan membuat dan mengonfigurasi instance NSFetchRequest untuk menginisialisasi permintaan pengambilan asinkron. Permintaan pengambilan inilah yang akan dijalankan permintaan asinkron di latar belakang.

1
// Initialize Fetch Request

2
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"TSPItem"];
3
4
// Add Sort Descriptors

5
[fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:YES]]];

Untuk menginisialisasi instance NSAsynchronousFetchRequest, kami memanggil initWithFetchRequest:completionBlock:, dimasukan di fetchRequest dan blok completion.

1
// Initialize Asynchronous Fetch Request

2
NSAsynchronousFetchRequest *asynchronousFetchRequest = [[NSAsynchronousFetchRequest alloc] initWithFetchRequest:fetchRequest completionBlock:^(NSAsynchronousFetchResult *result) {
3
    dispatch_async(dispatch_get_main_queue(), ^{
4
        // Process Asynchronous Fetch Result

5
        [weakSelf processAsynchronousFetchResult:result];
6
    });
7
}];

Blok completion dipanggil ketika permintaan pengambilan asinkron telah selesai menjalankan permintaan pengambilannya. Blok completion mengambil satu argumen tipe NSAsynchronousFetchResult, yang berisi hasil kueri serta referensi ke permintaan pengambilan asinkron asli.

Di blok completion, kami memanggil processAsynchronousFetchResult:, dimasukan di objek NSAsynchronousFetchResult. Kami akan melihat metode helper ini dalam beberapa saat.

Menjalankan permintaan pengambilan asinkron hampir identik dengan cara kami menjalankan NSBatchUpdateRequest. Kami memanggil executeRequest:error: pada konteks objek terkelola, dimasukan di permintaan pengambilan asinkron dan pointer ke objek NSError.

1
[self.managedObjectContext performBlock:^{
2
    // Execute Asynchronous Fetch Request

3
    NSError *asynchronousFetchRequestError = nil;
4
    NSAsynchronousFetchResult *asynchronousFetchResult = (NSAsynchronousFetchResult *)[weakSelf.managedObjectContext executeRequest:asynchronousFetchRequest error:&asynchronousFetchRequestError];
5
    
6
    if (asynchronousFetchRequestError) {
7
        NSLog(@"Unable to execute asynchronous fetch result.");
8
        NSLog(@"%@, %@", asynchronousFetchRequestError, asynchronousFetchRequestError.localizedDescription);
9
    }
10
}];

Perhatikan bahwa kami menjalankan permintaan pengambilan asinkron dengan memanggil performBlock: pada konteks objek terkelola. Meskipun ini tidak sepenuhnya diperlukan karena metode viewDidLoad, di mana kami membuat dan mengeksekusi permintaan pengambilan asinkron, dipanggil pada thread utama, itu kebiasaan yang baik dan praktik terbaik untuk melakukannya.

Meskipun permintaan pengambilan asinkron dijalankan di latar belakang, perhatikan bahwa metode executeRequest:error: segera kembalikan, menyerahkan kami objek NSAsynchronousFetchResult. Setelah permintaan pengambilan asinkron selesai, objek NSAsynchronousFetchResult yang sama diisi dengan hasil permintaan pengambilan.

Akhirnya, kami memeriksa apakah permintaan pengambilan asinkron dijalankan tanpa masalah dengan memeriksa apakah objek NSError sama dengan nil.

Langkah 4: Memproses Hasil Ambil Asinkron

Metode processAsynchronousFetchResult: tidak lebih dari metode helper di mana kami memproses hasil permintaan pengambilan asinkron. Kami menetapkan properti items view controller dengan konten properti finalResult hasil dan memuat kembali tampilan tabel.

1
- (void)processAsynchronousFetchResult:(NSAsynchronousFetchResult *)asynchronousFetchResult {
2
    if (asynchronousFetchResult.finalResult) {
3
        // Update Items

4
        [self setItems:asynchronousFetchResult.finalResult];
5
        
6
        // Reload Table View

7
        [self.tableView reloadData];
8
    }
9
}

Langkah 5: Bangun dan Jalankan

Bangun proyek dan jalankan aplikasi di Simulator iOS. Anda mungkin terkejut melihat aplikasi Anda berhenti ketika mencoba mengeksekusi permintaan pengambilan asinkron. Untungnya, output di konsol memberi tahu kami apa yang salah.

1
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'NSConfinementConcurrencyType context <NSManagedObjectContext: 0x7fce3a731e60> cannot support asynchronous fetch request <NSAsynchronousFetchRequest: 0x7fce3a414300> with fetch request <NSFetchRequest: 0x7fce3a460860> (entity: TSPItem; predicate: ((null)); sortDescriptors: ((

2
    "(createdAt, ascending, compare:)"

3
)); type: NSManagedObjectResultType; ).'

Jika Anda belum membaca artikel tentang Core Data dan konkurensi, Anda mungkin bingung dengan apa yang Anda baca. Ingat bahwa Core Data mendeklarasikan tiga tipe konkurensi, NSConfinementConcurrencyType, NSPrivateQueueConcurrencyType, dan NSMainQueueConcurrencyType. Setiap kali Anda membuat konteks objek terkelola dengan memanggil metode kelas init , tipe konkurensi konteks objek terkelola yang dihasilkan sama dengan NSConfinementConcurrencyType. Ini adalah tipe konkurensi default.

Masalahnya, bagaimanapun, adalah pengambilan asinkron tidak sesuai dengan tipe NSConfinementConcurrencyType. Tanpa terlalu banyak detail, penting untuk mengetahui bahwa permintaan pengambilan asinkron perlu menggabungkan hasil permintaan pengambilannya dengan konteks objek terkelola yang menjalankan permintaan pengambilan asinkron. Perlu mengetahui antrian pengiriman mana yang dapat melakukan ini dan itu sebabnya hanya NSPrivateQueueConcurrencyType dan NSMainQueueConcurrencyType mendukung pengambilan asinkron. Solusinya sangat sederhana.

Langkah 6: Mengkonfigurasi Konteks Objek yang Dikelola

Buka TSPAppDelegate.m dan perbarui metode managedObjectContext seperti yang ditunjukkan di bawah ini.

1
- (NSManagedObjectContext *)managedObjectContext {
2
    if (_managedObjectContext) {
3
        return _managedObjectContext;
4
    }
5
    
6
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
7
    
8
    if (coordinator) {
9
        _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
10
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
11
    }
12
    
13
    return _managedObjectContext;
14
}

Satu-satunya perubahan yang kami buat adalah mengganti metode init dengan initWithConcurrencyType:, dengan memasukan NSMainQueueConcurrencyType sebagai argumen. Ini berarti bahwa konteks objek yang dikelola hanya dapat diakses dari thread utama. Ini berfungsi baik selama kita menggunakan metode performBlock: atau performBlockAndWait: untuk mengakses konteks objek yang dikelola.

Jalankan proyek sekali lagi untuk memastikan bahwa perubahan kami memang telah menyelesaikan masalah.

4. Menampilkan Kemajuan

Kelas NSAsynchronousFetchRequest menambahkan dukungan untuk memantau kemajuan permintaan pengambilan dan bahkan dimungkinkan untuk membatalkan permintaan pengambilan asinkron, misalnya, jika pengguna memutuskan bahwa terlalu lama untuk menyelesaikannya.

Kelas NSAsynchronousFetchRequest memanfaatkan kelas NSProgress untuk pelaporan kemajuan serta membatalkan permintaan pengambilan asinkron. Kelas NSProgress, tersedia sejak iOS 7 dan OS X 10.9, adalah cara cerdas untuk memantau kemajuan suatu tugas tanpa harus secara ketat memasangkan tugas ke antarmuka pengguna.

Kelas NSProgress juga mendukung pembatalan, yang merupakan bagaimana permintaan pengambilan asinkron dapat dibatalkan. Mari kita cari tahu apa yang perlu kita lakukan untuk mengimplementasikan pelaporan kemajuan untuk permintaan pengambilan asinkron.

Langkah 1: Menambahkan SVProgressHUD

Kami akan menunjukkan kepada pengguna kemajuan permintaan pengambilan asinkron menggunakan pustaka SVProgressHUD milik Sam Vermette. Unduh perpustakaan dari GitHub dan tambahkan folder SVProgressHUD ke proyek Xcode Anda.

Langkah 2: Menyiapkan NSProgress

Dalam artikel ini, kami tidak akan mengeksplorasi kelas NSProgress secara mendetail, tetapi jangan ragu untuk membaca lebih lanjut tentang hal itu dalam dokumentasi. Kami membuat instance NSProgress di blok yang kami serahkan ke metode performBlock: dalam metode viewDidLoad view controller.

1
// Create Progress

2
NSProgress *progress = [NSProgress progressWithTotalUnitCount:1];
3
4
// Become Current

5
[progress becomeCurrentWithPendingUnitCount:1];

Anda mungkin terkejut bahwa kami menetapkan jumlah unit menjadi 1. Alasannya sederhana. Ketika Core Data mengeksekusi permintaan pengambilan asinkron, ia tidak tahu berapa banyak record yang akan ditemukan di store persisten. Ini juga berarti bahwa kami tidak akan dapat menunjukkan kemajuan relatif kepada pengguna — persentase. Sebagai gantinya, kami akan menunjukkan kepada pengguna kemajuan absolut — jumlah record yang telah ditemukan.

Anda bisa memperbaiki masalah ini dengan melakukan permintaan pengambilan untuk mengambil jumlah record sebelum Anda menjalankan permintaan pengambilan yang asinkron. Saya lebih suka untuk tidak melakukan ini, karena ini juga berarti bahwa mengambil record dari store persisten membutuhkan waktu lebih lama untuk diselesaikan karena permintaan pengambilan ekstra di awal.

Langkah 3: Menambahkan Observer

Saat kami menjalankan permintaan pengambilan asinkron, kami segera menyerahkan objek NSAsynchronousFetchResult. Objek ini memiliki properti progress, yang bertipe NSProgress. Properti progress inilah yang perlu kita amati jika kita ingin menerima pembaruan kemajuan.

1
// Execute Asynchronous Fetch Request

2
[self.managedObjectContext performBlock:^{
3
    // Create Progress

4
    NSProgress *progress = [NSProgress progressWithTotalUnitCount:1];
5
    
6
    // Become Current

7
    [progress becomeCurrentWithPendingUnitCount:1];
8
    
9
    // Execute Asynchronous Fetch Request

10
    NSError *asynchronousFetchRequestError = nil;
11
    NSAsynchronousFetchResult *asynchronousFetchResult = (NSAsynchronousFetchResult *)[self.managedObjectContext executeRequest:asynchronousFetchRequest error:&asynchronousFetchRequestError];
12
    
13
    if (asynchronousFetchRequestError) {
14
        NSLog(@"Unable to execute asynchronous fetch result.");
15
        NSLog(@"%@, %@", asynchronousFetchRequestError, asynchronousFetchRequestError.localizedDescription);
16
    }
17
    
18
    // Add Observer

19
    [asynchronousFetchResult.progress addObserver:self forKeyPath:@"completedUnitCount" options:NSKeyValueObservingOptionNew context:ProgressContext];
20
    
21
    // Resign Current

22
    [progress resignCurrent];
23
}];

Perhatikan bahwa kami memanggil resignCurrent pada objek progress untuk menyeimbangkan yang sebelumnya panggilan becomeCurrentWithPendingUnitCount:. Perlu diingat bahwa kedua metode ini perlu dijalankan pada thread yang sama.

Langkah 4: Menghapus Observer

Di blok completion permintaan pengambilan asinkron, kami menghapus observer dan mengabaikan progres HUD.

1
// Initialize Asynchronous Fetch Request

2
NSAsynchronousFetchRequest *asynchronousFetchRequest = [[NSAsynchronousFetchRequest alloc] initWithFetchRequest:fetchRequest completionBlock:^(NSAsynchronousFetchResult *result) {
3
    dispatch_async(dispatch_get_main_queue(), ^{
4
        // Dismiss Progress HUD

5
        [SVProgressHUD dismiss];
6
        
7
        // Process Asynchronous Fetch Result

8
        [weakSelf processAsynchronousFetchResult:result];
9
        
10
        // Remove Observer

11
        [result.progress removeObserver:weakSelf forKeyPath:@"completedUnitCount" context:ProgressContext];
12
    });
13
}];

Sebelum kita menerapkan observeValueForKeyPath:ofObject:change:context, kita perlu menambahkan pernyataan impor untuk pustaka SVProgressHUD, mendeklarasikan variabel statis ProgressContext yang kita berikan sebagai konteks saat menambahkan dan menghapus pengamat, dan menunjukkan kemajuan HUD sebelum membuat permintaan pengambilan asinkron.

1
#import "SVProgressHUD/SVProgressHUD.h"
1
static void *ProgressContext = &ProgressContext;
1
- (void)viewDidLoad {
2
    [super viewDidLoad];
3
    
4
    // Helpers

5
    __weak TSPViewController *weakSelf = self;
6
    
7
    // Show Progress HUD

8
    [SVProgressHUD showWithStatus:@"Fetching Data" maskType:SVProgressHUDMaskTypeGradient];
9
    
10
    // Initialize Fetch Request

11
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"TSPItem"];
12
    
13
    // Add Sort Descriptors

14
    [fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:YES]]];
15
    
16
    // Initialize Asynchronous Fetch Request

17
    NSAsynchronousFetchRequest *asynchronousFetchRequest = [[NSAsynchronousFetchRequest alloc] initWithFetchRequest:fetchRequest completionBlock:^(NSAsynchronousFetchResult *result) {
18
        dispatch_async(dispatch_get_main_queue(), ^{
19
            // Dismiss Progress HUD

20
            [SVProgressHUD dismiss];
21
            
22
            // Process Asynchronous Fetch Result

23
            [weakSelf processAsynchronousFetchResult:result];
24
            
25
            // Remove Observer

26
            [result.progress removeObserver:weakSelf forKeyPath:@"completedUnitCount" context:ProgressContext];
27
        });
28
    }];
29
    
30
    // Execute Asynchronous Fetch Request

31
    [self.managedObjectContext performBlock:^{
32
        // Create Progress

33
        NSProgress *progress = [NSProgress progressWithTotalUnitCount:1];
34
        
35
        // Become Current

36
        [progress becomeCurrentWithPendingUnitCount:1];
37
        
38
        // Execute Asynchronous Fetch Request

39
        NSError *asynchronousFetchRequestError = nil;
40
        NSAsynchronousFetchResult *asynchronousFetchResult = (NSAsynchronousFetchResult *)[weakSelf.managedObjectContext executeRequest:asynchronousFetchRequest error:&asynchronousFetchRequestError];
41
        
42
        if (asynchronousFetchRequestError) {
43
            NSLog(@"Unable to execute asynchronous fetch result.");
44
            NSLog(@"%@, %@", asynchronousFetchRequestError, asynchronousFetchRequestError.localizedDescription);
45
        }
46
        
47
        // Add Observer

48
        [asynchronousFetchResult.progress addObserver:self forKeyPath:@"completedUnitCount" options:NSKeyValueObservingOptionNew context:ProgressContext];
49
        
50
        // Resign Current

51
        [progress resignCurrent];
52
    }];
53
}

Langkah 5: Pelaporan Kemajuan

Yang tersisa untuk kita lakukan adalah mengimplementasikan metode observeValueForKeyPath:ofObject:change:context:. Kami memeriksa apakah konteksnya sama dengan ProgressContext, membuat objek status dengan mengekstraksi jumlah record  yang diselesaikan dari dictionary change, dan memperbarui progres HUD. Perhatikan bahwa kami memperbarui antarmuka pengguna pada thread utama.

1
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
2
    if (context == ProgressContext) {
3
        dispatch_async(dispatch_get_main_queue(), ^{
4
            // Create Status

5
            NSString *status = [NSString stringWithFormat:@"Fetched %li Records", (long)[[change objectForKey:@"new"] integerValue]];
6
            
7
            // Show Progress HUD

8
            [SVProgressHUD setStatus:status];
9
        });
10
    }
11
}

5. Data Dummy

Jika kita ingin menguji aplikasi kita dengan benar, kita membutuhkan lebih banyak data. Meskipun saya tidak merekomendasikan menggunakan pendekatan berikut dalam aplikasi produksi, ini adalah cara cepat dan mudah untuk mengisi database dengan data.

Buka TSPAppDelegate.m dan perbarui metode application:didFinishLaunchingWithOptions seperti yang ditunjukkan di bawah ini. Metode populateDatabase adalah metode helper sederhana di mana kami menambahkan data dummy ke database.

1
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
2
    // Populate Database

3
    [self populateDatabase];
4
    
5
    ...
6
    
7
    return YES;
8
}

Implementasinya sangat mudah. Karena kami hanya ingin memasukkan data dummy sekaligus, kami memeriksa database default pengguna untuk kunci @"didPopulateDatabase". Jika kunci tidak disetel, kami memasukkan data dummy.

1
- (void)populateDatabase {
2
    // Helpers

3
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
4
    if ([ud objectForKey:@"didPopulateDatabase"]) return;
5
    
6
    for (NSInteger i = 0; i < 1000000; i++) {
7
        // Create Entity

8
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"TSPItem" inManagedObjectContext:self.managedObjectContext];
9
        
10
        // Initialize Record

11
        NSManagedObject *record = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];
12
        
13
        // Populate Record

14
        [record setValue:[NSString stringWithFormat:@"Item %li", (long)i] forKey:@"name"];
15
        [record setValue:[NSDate date] forKey:@"createdAt"];
16
    }
17
    
18
    // Save Managed Object Context

19
    [self saveManagedObjectContext];
20
    
21
    // Update User Defaults

22
    [ud setBool:YES forKey:@"didPopulateDatabase"];
23
}

Jumlah record penting. Jika Anda berencana untuk menjalankan aplikasi pada Simulator iOS, maka boleh saja untuk memasukkan 100.000 atau 1.000.000 record. Ini tidak akan berfungsi dengan baik pada perangkat fisik dan akan terlalu lama untuk diselesaikan.

Di dalam for loop, kami membuat objek yang dikelola dan mengisinya dengan data. Perhatikan bahwa kami tidak menyimpan perubahan konteks objek terkelola selama setiap iterasi dari perulangan for.

Terakhir, kami memperbarui database default pengguna untuk memastikan database tidak terisi saat aplikasi diluncurkan berikutnya.

Hebat. Jalankan aplikasi di iOS Simulator untuk melihat hasilnya. Anda akan melihat bahwa dibutuhkan beberapa saat untuk permintaan pengambilan asinkron untuk mulai mengambil record dan memperbarui kemajuan HUD.

6. Melanggar Perubahan

Dengan mengganti kelas results controller yang diambil dengan permintaan pengambilan asinkron, kami telah merusak beberapa bagian aplikasi. Misalnya, mengetuk tanda centang item yang harus dilakukan sepertinya tidak berfungsi lagi. Saat basis data sedang diperbarui, antarmuka pengguna tidak mencerminkan perubahan. Solusinya cukup mudah untuk diperbaiki dan saya akan menyerahkannya kepada Anda untuk mengimplementasikan solusinya. Anda sekarang harus memiliki pengetahuan yang cukup untuk memahami masalah dan menemukan solusi yang sesuai.

Kesimpulan

Saya yakin Anda setuju bahwa pengambilan asinkron secara mengejutkan mudah digunakan. Pengangkatan berat dilakukan oleh Core Data, yang berarti bahwa tidak perlu secara manual menggabungkan hasil permintaan pengambilan asinkron dengan konteks objek yang dikelola. Satu-satunya tugas Anda adalah memperbarui antarmuka pengguna ketika asynchronous mengambil permintaan dari Anda. Bersama dengan pembaruan batch, ini merupakan tambahan yang bagus untuk kerangka kerja Data Core.

Artikel ini juga menyimpulkan seri ini tentang Core Data. Anda telah belajar banyak tentang kerangka kerja Core Data dan Anda tahu semua hal penting untuk menggunakan Core Data dalam aplikasi nyata. Core Data adalah kerangka kerja yang kuat dan, dengan rilis iOS 8, Apple telah menunjukkan kepada kami bahwa itu menjadi lebih baik setiap tahun.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.