Bir Uçtan Yeniden Kullanılabilir UITableViewCell Yükleme


89

Http://forums.macrumors.com/showthread.php?t=545061 adresinde bulunan iş parçacığında açıklanan tekniği kullanarak özel UITableViewCells tasarlayabiliyorum ve bunları düzgün bir şekilde yükleyebiliyorum . Ancak, bu yöntemi kullanmak artık hücreyi bir reuseIdentifier ile başlatmanıza izin vermez; bu, her aramada her hücrenin tamamen yeni örneklerini oluşturmanız gerektiği anlamına gelir. Yeniden kullanım için belirli hücre türlerini hala önbelleğe almanın iyi bir yolunu bulan, ancak yine de onları Arayüz Oluşturucu'da tasarlayabilen var mı?

Yanıtlar:


74

Sadece uygun yöntem imzasına sahip bir yöntem uygulayın:

- (NSString *) reuseIdentifier {
  return @"myIdentifier";
}

Bu yöntem nerede uygulanmalı?
Krishnan


5
Bu riskli. Hücre alt sınıfınızın iki alt sınıfına sahipseniz ve bunların ikisini de tek bir tablo görünümünde kullanırsanız ne olur? Yeniden kullanım tanımlayıcı çağrısını super'e gönderirlerse, yanlış türdeki bir hücreyi sıradan çıkarırsınız .............. reuseIdentifier yöntemini geçersiz kılmanız gerektiğini, ancak bunun yerine bir tanımlayıcı döndürmesini sağlamanız gerektiğini düşünüyorum. dize.
SK9

3
Benzersiz olduğundan emin olmak için şunları yapabilirsiniz:return NSStringFromClass([self class]);
ivanzoid

119

Aslında, Arayüz Oluşturucu'da hücreyi oluşturduğunuz için, yeniden kullanım tanımlayıcısını oraya ayarlayın:

IB_reuse_identifier

Veya Xcode 4 çalıştırıyorsanız, Nitelikler denetçisi sekmesini kontrol edin:

görüntü açıklamasını buraya girin

(Düzenleme: XIB'niz XCode tarafından oluşturulduktan sonra, boş bir UIView içerir, ancak bir UITableViewCell'e ihtiyacımız vardır; bu nedenle UIView'ı manuel olarak kaldırmanız ve bir Tablo Görüntüleme Hücresi eklemeniz gerekir. Elbette, IB, bir UIView.)


Bu Uç tarafından oluşturulan Hücreleri birden fazla hücre için kullanırsam, Tanımlayıcıları ne ayarlarım? Bu, aynı tanımlayıcılara sahip iki hücreye sahip olmamızı sağlayacaktır.
Krishnan

4
Bunu benzersiz bir tanımlayıcı olarak düşünmeyin - daha çok bir tür adı gibi düşünün.
Tim Keating

Xcode 4.3.3'teki yerleşik arabirim oluşturucu aracılığıyla bir tanımlayıcı ayarlama seçeneğini görmüyorum. Sınıfı kesinlikle UITableViewCell alt sınıfıma ayarlıyorum. Ben mi özlüyorum yoksa gitti mi?
Tyler

3
Tamam, sorunumu çözdüm. Arabirim oluşturucuda (Xcode 4 içinde) bir UIView nesnesiyle başlarsanız ve sınıfını UITableViewCell olarak değiştirirseniz, yeniden kullanım tanımlayıcısı gibi hücreye özgü özellikleri alamazsınız. Bunu elde etmek için, boş bir xib ile başlamanız ve daha sonra düzenleyebileceğiniz hücreye özgü özelliklere sahip olan bir tablo hücresi nesnesine sürüklemeniz gerekir.
Tyler

1
@Krishnan Bunu şu şekilde düşünün - X tanımlayıcısına sahip tablo görünümü hücresini oluşturduğunuzda, "Bana X etiketli havuzdan bir hücre verin" diyorsunuz. Havuz varsa ve içinde boş bir hücre varsa, size verir. Aksi takdirde, havuzu oluşturur (gerekirse), sonra hücreyi haber verir, "X" olarak etiketler ve sonra size verir. Böylece hücreler benzersiz OLABİLİR - örneğin, belirli bir tanımlayıcıya sahip yalnızca bir hücreye sahip bir havuz oluşturabilirsiniz - ancak kitaplık, bellek ayırma / ayırma işleminden kaçınmak için ücretsiz bir liste benzeri strateji kullanır.
Tim Keating

66

Şimdi, iOS 5'te bunun için uygun bir UITableView yöntemi var:

- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier

10
Kabul edilen cevap dahil olmak üzere bu konudaki diğer cevaplar güncel olmayan tavsiyeler içeriyor.
Kaelin Colclasure

bu geriye dönük uyumlu mu? Demek istediğim, SDK 5.0 ile bir uygulama geliştirirsem ve minimum 4.0'ı hedeflersem, uygulama örneğin iOS 4.0 yüklü cihazlarda çalışır mı?
Abolfoooud

1
Hayır, iOS 5.0'daki herhangi bir yeni API gibi geriye dönük olarak uyumlu değildir.
marzapower

bunu denetleyicinize nasıl entegre edeceğinize dair bir örnek: mindfiresolutions.com/…
mblackwell8

47

Bu kodu başlangıçta nerede bulduğumu hatırlayamıyorum, ancak şu ana kadar benim için harika çalışıyor.

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"CustomTableCell";
    static NSString *CellNib = @"CustomTableCellView";

    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
        cell = (UITableViewCell *)[nib objectAtIndex:0];
    }

    // perform additional custom work...

    return cell;
}

Örnek Arabirim Oluşturucu kurulumu ...

alternatif metin


12

Bu soruya verdiğim cevaba bakın:

NSCell alt sınıflarını Interface Builder'da tasarlamak mümkün müdür?

IB'de bir UITableViewCell tasarlamak sadece mümkün değildir, arzu edilir çünkü aksi takdirde birden fazla elemanın tüm manuel kablolaması ve yerleştirilmesi çok sıkıcıdır. Mümkün olduğunda tüm öğeleri opak yapmaya dikkat ettiğiniz sürece performans iyidir. Yeniden kullanım kimliği, UITableViewCell'in özellikleri için IB'de ayarlanır, ardından sırayı kaldırmaya çalışırken kodda eşleşen yeniden kullanım kimliğini kullanırsınız.

Ayrıca geçen yıl WWDC'deki bazı sunuculardan IB'de tablo görünümü hücreleri yapmamanız gerektiğini duydum, ama bu bir sürü saçmalık.


2
Şeffaflığa ihtiyacınız varsa ve iyi kaydırma performansı istiyorsanız, IB'de tablo görünümü hücreleri yapmamalısınız. Belirli kullanıcı arayüzleri için şeffaflığa ihtiyacınız vardır (örneğin grafikler üzerinde metin oluşturmak için). Bazen eski (A4 öncesi) donanımda iyi bir kaydırma elde etmenin tek yolu, GPU'nun birden çok saydam katmanı birleştirmek zorunda kalmasını önlemek için kodda oluşturmaktır.
Nick Forge

2
Doğru, ancak bununla bile, IB'de yerleşik hücrelerin daha kolay bakımını sağlamak için eski cihazlarda performansın biraz düşmesine izin vermeniz daha iyi olabilir. Bu tekniği, özel bir çizim yöntemiyle birleştirmekten kaçınmak için daha sonra öğeleri çizdiğiniz bir şablon hücre olarak da kullanabilirsiniz.
Kendall Helmstetter Gelner


6

İşte başka bir seçenek:

NSString * cellId = @"reuseCell";  
//...
NSArray * nibObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomTableCell" owner:nil options:nil];

for (id obj in nibObjects)
{
    if ([obj isKindOfClass:[CustomTableCell class]])
    {
        cell = obj;
        [cell setValue:cellId forKey:@"reuseIdentifier"];
        break;
    }
}

Bunun, UITableViewCellbenzersiz bir değer ayarlamak için özelliğinizin alt sınıflara ayrılmasını gerektirmeyen şimdiye kadar yayınlanan tek çözüm olduğunu unutmayın reuseIdentifer. Bence asıl operasyonun aradığı şey buydu.
charshep

Umarım Apple bunu kullanmak için başvurumu reddetmez ... Bunu "statik" hücreler elde etmek için kullanıyorum çünkü tablo görünümümde bir hücreyi doldurma işlemi oldukça yavaş. Bu şekilde sadece bir kez çalıştırmam gerekiyor (her satıra farklı bir tanımlayıcı vererek). Teşekkür ederim!
Ricard Pérez del Campo

Bunu manuel olarak ayarlamak için UITableViewCell yöntemi olmadığı için çok yararlıdır!
Jesse

2

Özel görünüm hücrelerimi benzer bir şekilde oluşturuyorum - hücreyi bir IBOutlet aracılığıyla bağlamam dışında.

[nib objectAt...]Yaklaşım dizideki öğelerin pozisyonlarına değişikliklere açık olduğu.

UIViewControllerSadece denedim ve güzel yeterince çalışır - yaklaşımdır iyidir.

FAKAT...

Her durumda initWithStyle yapıcı çağrılmaz, bu nedenle varsayılan başlatma yapılmaz.

initWithCoderVeya kullanımıyla ilgili çeşitli yerler okudum awakeFromNib, ancak bunlardan herhangi birinin doğru yol olduğuna dair kesin bir kanıt yok.

Yöntemde bazı başlatma yöntemlerini açıkça çağırmanın dışında, cellForRowAtIndexPathbuna henüz bir cevap bulamadım.


awakeFromNib, bir NIB'den yüklenen bir nesneye tepki vermenin doğru yoludur.
Jon Hess

2

Bir süre önce blog.atebits.com adresinde bu konuyla ilgili harika bir blog yazısı buldum ve o zamandan beri tüm UITableViewCells'imi yapmak için Loren Brichter ABTableViewCell sınıfını kullanmaya başladım.

Tüm widget'larınızı yerleştirmek için basit bir kapsayıcı UIView ile sonuçlanırsınız ve kaydırma işlemi ışık hızında.

Umarım bu yararlıdır.


2

Bu teknik de işe yarar ve bellek yönetimi için görüntüleme denetleyicinizde ilginç bir ivar gerektirmez. Burada, özel tablo görünümü hücresi "CustomCell.xib" adlı bir xib'de bulunur.

 static NSData *sLoadedCustomCell = nil;

 cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
 if (cell == nil) 
 {
   if (sLoadedCustomCell == nil) 
   {        
      // Load the custom table cell xib
      // and extract a reference to the cell object returned
      // and cache it in a static to avoid reloading the nib again.

      for (id loadedObject in [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil]) 
      {
        if ([loadedObject isKindOfClass:[UITableViewCell class]]) 
        {
          sLoadedCustomCell = [[NSKeyedArchiver archivedDataWithRootObject: loadedObject] retain];
          break;
        }
    }
    cell = (UITableViewCell *)[NSKeyedUnarchiver unarchiveObjectWithData: sLoadedCustomCell];
  }

1
Arşivleme ve arşivden çıkarma tamamen gereksizdir.
Bryan Henry

1
Hücreyi kuyruğu çözülemediğinde ucundan yüklemekte sorun yoksa arşivleme / arşivden çıkarma gereksizdir. Bununla birlikte, hücreyi yalnızca ucundan tam olarak bir kez yüklemek istiyorsanız , onu bellekte önbelleğe almanız gerekir. Bu önbelleğe alma işlemini NSKeyedArchiving kullanarak gerçekleştiriyorum çünkü UITableViewCell NSCopying'i uygulamıyor.
Bill Garrison

1
Tüm söylenenler, hücreyi yüklemek için UINib'i kullanmak aynı etkiyi sağlar: diskten bir kez yükle, daha sonra bellekten yükle.
Bill Garrison

2

Louis yöntemi benim için çalıştı. Bu, uçtan UITableViewCell'i oluşturmak için kullandığım kod:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"CustomCellId"];

    if (cell == nil) 
    {
        UIViewController *c = [[UIViewController alloc] initWithNibName:@"CustomCell" bundle:nil];
        cell = (PostCell *)c.view;
        [c release];
    }

    return cell;
}

2
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *simpleTableIdentifier = @"CustomCell";

CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    cell = [nib objectAtIndex:0];

    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}         

return cell;
}

1

Gustavogb çözümü benim için çalışmıyor, denediğim şey:

ChainesController *c = [[ChainesController alloc] initWithNibName:@"ChainesController" bundle:nil];
[[NSBundle mainBundle] loadNibNamed:@"ChaineArticleCell" owner:c options:nil];
cell = [c.blogTableViewCell retain];
[c release];

İşe yarıyor gibi görünüyor. BlogTableViewCell, hücre için IBOutlet'tir ve ChainesController dosyanın sahibidir.


1

UITableView belgelerinden dequeueWithReuseIdentifier : "Yeniden kullanılacak hücre nesnesini tanımlayan bir dize. Varsayılan olarak, yeniden kullanılabilir bir hücrenin tanımlayıcısı sınıf adıdır, ancak bunu herhangi bir rasgele değere değiştirebilirsiniz."

-ReuseIdentifer'i geçersiz kılmak risklidir. Hücre alt sınıfınızın iki alt sınıfına sahipseniz ve bunların ikisini de tek bir tablo görünümünde kullanırsanız ne olur? Yeniden kullanım tanımlayıcı çağrısını super'e gönderirlerse, yanlış türdeki bir hücreyi sıradan çıkarırsınız .............. reuseIdentifier yöntemini geçersiz kılmanız gerektiğini, ancak bunun yerine bir tanımlayıcı döndürmesini sağlamanız gerektiğini düşünüyorum. dize. Veya, biri belirtilmemişse, sınıfı bir dizge olarak döndürmesini sağlayın.


0

Değeri ne olursa olsun, bir iPhone mühendisine bunu iPhone Teknik Konuşmalarından birinde sordum. Cevabı, "Evet, hücreler oluşturmak için IB'yi kullanmak mümkün. Ama yapma. Lütfen yapma."


1
Bu garip. NY konuşmasındaki görüşmelerden en az ikisinde IB'de oluşturulan hücreleri kullanan demo kodu vardı.
Shawn Craver

3
Apple'ın Advanced Table View Cells örnek projesinde hücreler oluşturmak için IB kullandıkları için buna inandığımdan emin değilim.
iwasrobbed

Bunun için teşekkürler. Bunu her yaptığımda sorunlarla karşılaşıyorum. Sebebi bu olabilir
skorulis

Muhtemelen bu konuda yeterince bilgisi yoktu.
aryaxt

0

Ben Mosher ile bağlantılı olarak Apple'ın talimatlarını takip ettim (teşekkürler!) Ancak Apple'ın önemli bir noktayı atladığını gördüm. IB'de tasarladıkları nesne, ondan yükledikleri değişken gibi sadece bir UITableViewCell'dir. Ancak bunu gerçekten UITableViewCell'in özel bir alt sınıfı olarak ayarlarsanız ve alt sınıf için kod dosyalarını yazarsanız, kodda IBOutlet bildirimleri ve IBAction yöntemlerini yazabilir ve bunları IB'deki özel öğelerinize bağlayabilirsiniz. Bu öğelere erişmek için görünüm etiketlerini kullanmanıza gerek kalmaz ve istediğiniz her türlü çılgın hücreyi oluşturabilirsiniz. Cocoa Touch cenneti.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.