UITableViewController
Tek bir nesneye çok fazla sorumluluk koyduğu için kullanmaktan kaçınıyorum . Bu nedenle, UIViewController
alt sınıfı veri kaynağından ve temsilcisinden ayırırım. Görünüm denetleyicisinin sorumluluğu, tablo görünümünü hazırlamak, verileri içeren bir veri kaynağı oluşturmak ve bunları birbirine bağlamaktır. Tablo görüntüsünün temsil edilme şeklini değiştirmek, görünüm denetleyicisini değiştirmeden yapılabilir ve aslında aynı görünüm denetleyicisi, tümü bu modeli izleyen birden fazla veri kaynağı için kullanılabilir. Benzer şekilde, uygulama iş akışını değiştirmek, tabloya ne olduğu konusunda endişelenmeden görüntüleme denetleyicisindeki değişiklikler anlamına gelir.
UITableViewDataSource
Ve UITableViewDelegate
protokolleri farklı nesnelere ayırmaya çalıştım , ancak bu genellikle temsilci üzerindeki hemen hemen her yöntemin veri kaynağının içine girmesi gerektiği için yanlış bir bölünme olarak sona eriyor (örneğin seçimde, temsilci, hangi nesnenin temsil ettiği nesneyi temsil ettiğini bilmek istiyor) seçili satır). Böylece hem veri kaynağı hem de temsilci olan tek bir nesne ile karşılaşıyorum. Bu nesne her zaman -(id)tableView: (UITableView *)tableView representedObjectAtIndexPath: (NSIndexPath *)indexPath
hem veri kaynağının hem de temsilci özelliklerinin ne üzerinde çalıştıklarını bilmeleri gereken bir yöntem sağlar .
Bu benim endişelerimin "seviye 0" ayrımı. Aynı tablo görünümünde farklı türdeki nesneleri temsil etmem gerekiyorsa, Seviye 1 devreye giriyor. Örnek olarak, Rehber uygulamasını yazmanız gerektiğini düşünün; tek bir kişi için, telefon numaralarını temsil eden satırlara, adresleri temsil eden diğer satırlara, e-posta adreslerini temsil eden diğerlerine vb. Sahip olabileceğinizi düşünün. Bu yaklaşımdan kaçınmak istiyorum:
- (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 …
}
Şimdiye kadar iki çözüm önerdi. Biri dinamik olarak bir seçici seçmektir:
- (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
}
Bu yaklaşımda, if()
yeni bir türü desteklemek için destansı ağacı düzenlemenize gerek yoktur - sadece yeni sınıfı destekleyen yöntemi ekleyin. Bu tablo görüntüsü, bu nesneleri temsil etmesi gereken veya onları özel bir şekilde sunması gereken tek şeyse, bu harika bir yaklaşımdır. Aynı nesneler farklı veri kaynaklarına sahip farklı tablolarda temsil edilecekse, hücre oluşturma yöntemlerinin veri kaynakları arasında paylaşılması gerektiğinden bu yaklaşım bozulur; bu yöntemleri sağlayan ortak bir üst sınıf tanımlayabilirsiniz veya şunları yapabilirsiniz:
@interface PhoneNumber (TableViewRepresentation)
- (UITableViewCell *)tableView: (UITableView *)tableView representationAsCellForRowAtIndexPath: (NSIndexPath *)indexPath;
@end
@interface Address (TableViewRepresentation)
//more of the same…
@end
Sonra veri kaynağı sınıfınızda:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
id object = [self tableView: tableView representedObjectAtIndexPath: indexPath];
return [object tableView: tableView representationAsCellForRowAtIndexPath: indexPath];
}
Bu, telefon numaralarını, adresleri vb. Görüntülemesi gereken herhangi bir veri kaynağının yalnızca bir tablo görüntüleme hücresi için hangi nesnenin temsil edildiğini sorabileceği anlamına gelir . Veri kaynağının artık görüntülenen nesne hakkında hiçbir şey bilmesine gerek yok.
"Ama bekle," Ben varsayımsal bir muhatap araya girdiğini duyuyorum ", bu MVC'yi kırmaz mı?
Hayır, MVC'yi kırmaz. Bu durumda kategorileri bir Dekoratör uygulaması olarak düşünebilirsiniz ; yani PhoneNumber
bir model sınıfı ama PhoneNumber(TableViewRepresentation)
bir görünüm kategorisi. Veri kaynağı (bir denetleyici nesnesi) model ve görünüm arasında aracılık eder, böylece MVC mimarisi hala tutar.
Bu kategorilerin kullanımını Apple'ın çerçevelerinde dekorasyon olarak da görebilirsiniz. NSAttributedString
bazı metinleri ve nitelikleri tutan bir model sınıfıdır. AppKit sağlar NSAttributedString(AppKitAdditions)
ve UIKit, NSAttributedString(NSStringDrawing)
bu model sınıflarına çizim davranışı katan dekoratör kategorileri sağlar .