Saya menghindari penggunaan UITableViewController
, karena menempatkan banyak tanggung jawab ke dalam satu objek. Oleh karena itu saya memisahkan UIViewController
subclass dari sumber data dan mendelegasikan. Tanggung jawab pengontrol tampilan adalah menyiapkan tampilan tabel, membuat sumber data dengan data, dan menyatukan semuanya. Mengubah cara tampilan tabel diwakili dapat dilakukan tanpa mengubah pengontrol tampilan, dan memang pengontrol tampilan yang sama dapat digunakan untuk beberapa sumber data yang semuanya mengikuti pola ini. Demikian pula, mengubah alur kerja aplikasi berarti perubahan pada pengontrol tampilan tanpa khawatir tentang apa yang terjadi pada tabel.
Saya sudah mencoba memisahkan protokol UITableViewDataSource
dan UITableViewDelegate
menjadi objek yang berbeda, tetapi yang biasanya berakhir dengan pembelahan palsu karena hampir setiap metode pada delegasi perlu menggali ke dalam sumber data (misalnya pada seleksi, delegasi perlu tahu objek apa yang diwakili oleh baris yang dipilih). Jadi saya berakhir dengan satu objek yang merupakan sumber data dan delegasi. Objek ini selalu menyediakan metode di -(id)tableView: (UITableView *)tableView representedObjectAtIndexPath: (NSIndexPath *)indexPath
mana sumber data dan aspek pendelegasian perlu mengetahui apa yang sedang mereka kerjakan.
Itu pemisahan "tingkat 0" saya. Level 1 bertunangan jika saya harus mewakili objek dari berbagai jenis dalam tampilan tabel yang sama. Sebagai contoh, bayangkan Anda harus menulis aplikasi Kontak — untuk satu kontak, Anda mungkin memiliki baris yang mewakili nomor telepon, baris lain yang mewakili alamat, yang lain mewakili alamat email, dan sebagainya. Saya ingin menghindari pendekatan ini:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
id object = [self tableView: tableView representedObjectAtIndexPath: indexPath];
if ([object isKindOfClass: [PhoneNumber class]]) {
//configure phone number cell
}
else if …
}
Dua solusi telah muncul sejauh ini. Pertama adalah membangun pemilih secara dinamis:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
id object = [self tableView: tableView representedObjectAtIndexPath: indexPath];
NSString *cellSelectorName = [NSString stringWithFormat: @"tableView:cellFor%@AtIndexPath:", [object class]];
SEL cellSelector = NSSelectorFromString(cellSelectorName);
return [self performSelector: cellSelector withObject: tableView withObject: object];
}
- (UITableViewCell *)tableView: (UITableView *)tableView cellForPhoneNumberAtIndexPath: (NSIndexPath *)indexPath {
// configure phone number cell
}
Dalam pendekatan ini, Anda tidak perlu mengedit if()
pohon epik untuk mendukung tipe baru - cukup tambahkan metode yang mendukung kelas baru. Ini adalah pendekatan yang bagus jika tampilan tabel ini adalah satu-satunya yang perlu mewakili objek-objek ini, atau perlu menyajikannya dengan cara khusus. Jika objek yang sama akan diwakili dalam tabel yang berbeda dengan sumber data yang berbeda, pendekatan ini rusak karena metode pembuatan sel perlu dibagi di seluruh sumber data — Anda bisa menentukan superclass umum yang menyediakan metode ini, atau Anda bisa melakukan ini:
@interface PhoneNumber (TableViewRepresentation)
- (UITableViewCell *)tableView: (UITableView *)tableView representationAsCellForRowAtIndexPath: (NSIndexPath *)indexPath;
@end
@interface Address (TableViewRepresentation)
//more of the same…
@end
Kemudian di kelas sumber data Anda:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
id object = [self tableView: tableView representedObjectAtIndexPath: indexPath];
return [object tableView: tableView representationAsCellForRowAtIndexPath: indexPath];
}
Ini berarti bahwa setiap sumber data yang perlu menampilkan nomor telepon, alamat, dll. Bisa saja bertanya objek apa pun yang diwakili untuk sel tampilan tabel. Sumber data itu sendiri tidak perlu lagi tahu apa-apa tentang objek yang ditampilkan.
"Tapi, tunggu," aku mendengar kata sela hipotetis, "bukankah itu merusak MVC? Apakah kamu tidak memasukkan detail tampilan ke dalam kelas model?"
Tidak, itu tidak merusak MVC. Anda dapat menganggap kategori dalam hal ini sebagai penerapan Dekorator ; begitu PhoneNumber
juga kelas model tetapi PhoneNumber(TableViewRepresentation)
merupakan kategori tampilan. Sumber data (objek pengontrol) memediasi antara model dan tampilan, sehingga arsitektur MVC masih berlaku.
Anda dapat melihat penggunaan kategori ini sebagai hiasan dalam kerangka kerja Apple juga. NSAttributedString
adalah kelas model, memegang beberapa teks dan atribut. AppKit menyediakan NSAttributedString(AppKitAdditions)
dan UIKit menyediakan NSAttributedString(NSStringDrawing)
, kategori dekorator yang menambahkan perilaku menggambar ke kelas model ini.