iPhone programlama ile ilgili olan bu ikinci yazımda, iPhone uygulamaları
geliştirirken en çok kullanılan bileşenlerden biri olan UITableView bileşeninin,
yani tabloların nasıl kullanılacağını göstereceğim. Önce bir liste
göstermekten başka bir şey yapmayan etkileşimsiz bir tabloyu çalışır
hale getirip, sonrasında bu tablonun sırasıyla satırlarına basıldığında
bir mesaj gösteren, satırları silinebilen ve satırlarının yerleri
değiştirilebilen hale nasıl getirilebileceğini adım adım göstereceğim.
Başlamak için tahmin edebileceğiniz üzere XCode'u açıp, View-based application türünden yeni bir proje yaratmanız gerekiyor. Bunun nasıl yapılacağını önceki yazımda göstermiştim. Ben projeye yine önceki yazımda olduğu gibi Ornek adını verdim, dosya adlarının uyuşması açısından aynısını yapmanızı tavsiye ederim.
Projeyi yarattıktan sonra yapmanız gereken ilk şey, "OrnekViewController.xib" adlı arayüz dosyasını Interface Builder (IB) ile açıp arayüzü tasarlamak. İlk etapta ihtiyacınız olan tek şey bir tablo. Bunun için Library penceresinden bir TableView bileşenini arayüze sürükleyip bırakın. View'iniz üzerinde aşağıdaki şekilde gösterildiği gibi yer tutucu değerler ile dolu bir tablo göreceksiniz. Daha sonra aşağıdaki şekilde göstermiş olduğum gibi koyduğunuz bu tabloyu seçin ve Inspector penceresindeki dataSource ve delegate Outlet'lerini, .xib dosyasının içeriğini gösteren penceredeki File's Owner nesnesine bağlayın. Bağlama işleminin kontrol tuşuna basılı tutarken sürükleyip bırakma ile yapıldığını önceki yazımda da göstermiştim.
Şimdi XCode'a dönüp bu tabloya koddan erişebilmenizi sağlayacak olan Outlet'i tanımlamanız gerekiyor. Ayrıca tablonun göstereceği verileri içeren bir diziye de ihtiyacınız var. Bunun için "OrnekViewController.h" dosyasını aşağıdaki hale getirin.
#import <UIKit/UIKit.h>
@interface OrnekViewController : UIViewController {}
@property (nonatomic, retain) IBOutlet UITableView* tablo;
@property (nonatomic, retain) NSMutableArray* dizi;
@end
Burada biri UITableView türünden bir nesneye, diğeri de dinamik bir diziyi temsil eden sınıf olan NSMutableArray türünden bir nesneye işaret edecek olan iki özellik tanımlamış olduk. Şimdi "OrnekViewController.m" dosyasını açıp içerisindeki gereksiz metodları sildikten sonra aşağıdaki hale getiriyoruz.
#import "OrnekViewController.h"
@implementation OrnekViewController
@synthesize tablo,dizi;
- (void)viewDidLoad
{
[super viewDidLoad];
self.dizi = [NSMutableArray arrayWithObjects:@"elma",@"armut",@"portakal",@"çilek",@"kiraz",@"muz",@"karpuz",@"kavun",nil];
tablo.rowHeight = 50;
}
- (void)viewDidUnload
{
self.tablo = nil;
}
- (void)dealloc
{
[tablo release];
[dizi release];
[super dealloc];
}
@end
viewDidLoad metodu, ViewController'ın kontrol ettiği view belleğe yüklendikten hemen sonra çağrılan bir metod. Ekran kullanıcıya gösterilmeden önce yapılması gereken işleri bu metodun içerisinde yapabilirsiniz. Benzer işlerin yapılması için kullanabileceğiniz daha mantıklı metodlar da var ancak burada onları kullanmaya gerek yok. Bu örnekte yaptığımız işler, tablonun göstereceği verileri içeren dizi değişkenini yaratıp içini meyve isimleriyle doldurmak ve tablonun satırlarının yüksekliğini 50 piksele ayarlamak. viewDidload ve dealloc metodlarında da, önceden yaratmış olduğumuz Outlet ve dizinin hafızadan silinmesini sağladık. Farkettiyseniz meyve isimleri sadece tırnak içerisinde değil, @"" içerisinde yazılı. Bunun sebebi Objective-c içerisinde bu şekilde kullandığınız String'lerin NSString* anlamına geliyor olması. Objective-c ile String'leri hep bu şekilde yazmanız gerekiyor.
Sonraki adım IB'ye dönüp, tanımlamış olduğunuz Outlet'i, arayüze koymuş olduğunuz tabloya bağlamak (File's Owner ikonundan tablomuza kontrol tuşuna basarak sürükle-bırak ile). Bu işlemi de yaptıkyan sonra File's Owner ikonuna tıklayarak ViewController'ınızı seçerseniz, Inspector penceresinin bağlantılar bölmesinin aşağıdaki şekilde olduğunu görmelisiniz. Eğer görmüyorsanız geriye dönüp bir şeyi unutup unutmadığınızı kontrol edin.
Şimdilik IB ile işiniz bitti. Tekrar XCode'a dönüp .m dosyası (Bundan sonra .m veya .h dosyası dediğimde "OrnekViewController" adındaki dosyaları kasdettiğimi anlarsınız artık heralde) içerisine tablonun dolmasını sağlayacak şu delegate metodlarını ekleyin.
// Tablonun bize kaç bölmeye sahip olacağını sorduğu metod
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Bölme sayısı bu örnekte 1
return 1;
}
// Tablonun bize toplam kaç satır göstereceğini sorduğu metod
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Satir sayısı dizinin eleman sayısı kadar olmalı
return dizi.count;
}
// Tablonun bize hangi satırda hangi hücrenin bulunması gerektiğini sorduğu metod
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Yarrattığımız hücreleri sonradan tekrar kullanabilmemizi sağlayacak olan bir kod belirliyoruz
static NSString *CellIdentifier = @"Hucre";
// Bellekte bu koda sahip olan herhangi bir hücre var mı diye bak
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Eğer öyle bir hücre yoksa yenisini yarat
if (cell == nil)
{
// Hücre yarat
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Satırlar seçilemesin (Bu satırı silerseniz seçtiğiniz satırlar mavi olur)
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Kaçıncı satır için hücre hazırladığımızı öğren
int satirNo = [indexPath indexAtPosition:1];
// Hücre içeriğini hazırla
cell.textLabel.text = [dizi objectAtIndex:satirNo];
// Hazırlanan hücreyi döndür
return cell;
}
Burada eklediğimiz metodların hepsi UITableViewDataSource protokolü içerisinde tanımlanmış. UITableView bileşeni de veri kaynağı olarak bu protokole uyan bir nesneye ihtiyaç duyuyor. Yani nasıl davranması gerektiğini bu metodları çağırıp, metodlardan dönen değerlere bakrak öğreniyor. Tabloda kaç bölme olduğunu numberOfSectionsInTableView: metodundan dönen değere bakarak, her bölmede kaç satır olduğunu tableView:numberofRowsInSection: metodundan dönen değere bakarak, hangi bölmenin hangi sütununda hangi hücrenin olması gerektiğini ise tableView:cellForRowAtIndexPath: metodundan dönen hücreye bakarak öğreniyor (Farkettiyseniz Objective-c de metod ismi diye bir şey yok. Methodun ismi parametrelerinin isimlerinin birleşiminden oluşuyor. Her parametreden sonra da bir : işareti var). Bu metodların implementasyonunu, tabloya dataSource olarak gösterdiğiniz sınıf içerisinde istediğiniz şekilde yaparak, tablonun dilediğiniz şekilde çalışmasını sağlayabilirsiniz. Yukarıdaki kodda tabloya, tek bölmeli ve dizinin eleman sayısı kadar satıra sahip olmasını söyledik. Hücreleri ise, her satırda dizinin ilgili elemanı gösterilecek şekilde yarattık. Hücrelerin içeriğini ayarlama işlemini, tablolar içerisinde varsayılan olarak bulunan textLabel adlı nesnenin içeriğini değiştirerek yaptık. Eğer programı bu haliyle çalıştırırsanız, aşağıdaki ekilde görüldüğü gibi, kodda vermiş olduğunuz meyveleri listeleyen, etkileşimsiz bir tablo görürsünüz.
Eğer kullanıcı tablonun bir satırına bastığında bir şey yapmak, mesela bir mesaj göstermek isterseniz, .m dosyasının içerisine aşağıdaki metodu ekleyebilirsiniz.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int satirNo = [indexPath indexAtPosition:1];
NSString* msg = [NSString stringWithFormat:@"%@ yiyelim",[dizi objectAtIndex:satirNo]];
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:nil message:msg delegate:nil cancelButtonTitle:@"Tamam" otherButtonTitles:nil];
[alert show];
[alert release];
}
Şimdi programı çalıştırıp satırlardan birine tıklarsanız şöyle bir manzara ile karşılaşırsınız.
Satır Silme ve Yer Değiştirme
Satır silme işlemini yapmanın iki farklı yolu var. Biri satır üzerinde parmağınızı soldan sağa götürdüğünüzde silme ikonu çıkarmak, diğeri de tabloyu edit (düzenleme) moduna sokup sildirmek. Öncelikle ilk metodu göstereceğim çünkü zaten ileride yapacağım yer değiştirme işlevselliği için tabloyu edit moduna sokmamız zaten gerekecek.
Satır silme işlemi için tek yapmanız gereken yine UITableViewDataSource protokolünde tanımlanmış olan tableView:commitEditingStyle:forRowAtIndexPath: metodunun aşağıdaki şekilde implementasyonunu yapmak. Açıklamaları kod içerisindeki yorumlarda yaptım.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Bu metod silme işlemi için mi çağırılmış kontrol et
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Hangi satırın silindiğini öğren ve satırı diziden de sil
int satirNo = [indexPath indexAtPosition:1];
[dizi removeObjectAtIndex:satirNo];
// Tabloyu güncelle
[tablo reloadData];
}
}
Uygulamayı bu haliyle çalıştırıp, parmağınızı herhangi bir satır üzerinde soldan sağa sürüklerseniz, aşağıdaki şekilde bir silme tuşu görecek, tuşa bastığınızda da satırın silindiğini göreceksiniz.
Şimdi gelelim tabloyu düzenleme moduna sokmaya. Tablo kendi kafasına göre düzenleme moduna giremeyeceğine göre, ona bunu ne zaman yapacağını söylemenizi sağlayacak bir şeye ihtiyacınız var. Bu ihtiyacı gidermenin en temiz yolu arayüzün alt kısmına yeni bir tuş eklemek. Tuşu ekledikten sonra .h dosyasını bir Outlet ve tuşa basıldığında çağrılacak olan bir metod tanımlayarak aşağıdaki hale getirin.
#import <UIKit/UIKit.h>
@interface OrnekViewController : UIViewController {}
@property (nonatomic, retain) IBOutlet UITableView* tablo;
@property (nonatomic, retain) IBOutlet UIButton* tus;
@property (nonatomic, retain) NSMutableArray* dizi;
-(IBAction)tusaBasildi;
@end
Sonrada tekrar .m dosyasına geçin, @synthesize satırına tuşu da ekleyin ve tuşa basıldığında çağrılacak olan metodun implementasyonunu aşağıdaki şekilde yapın.
-(IBAction)tusaBasildi
{
if (!tablo.editing)
{
tablo.editing = YES;
[tus setTitle:@"Düzenledim" forState:UIControlStateNormal];
}
else
{
tablo.editing = NO;
[tus setTitle:@"Düzenle" forState:UIControlStateNormal];
}
}
Burada yaptığımız tek şey tuşa basıldığında tabloyu düzenleme moduna sokmak ve tekrar basıldığında normal moduna geri döndürmek. Hangi modda olduğumuzu anlamak açısından tuşun üzerindeki yazıyı da duruma göre değiştirdik. Kodu bu haliyle çalıştırırıp tuşa basarsanız, tablonun aşağıda göstermiş olduğum düzenleme moduna geçtiğini görürsünüz. Bu modun işlevselliğini mutlaka kullandığınız bir uygulamada görmüşüsünüzdür. Soldaki tuşlardan birine basınca sağda silme tuşu çıkıyor ve ona basarak ilgili satırı silebiliyorsunuz.
Son olarak .m dosyası içerisinde tablo satırlarının yerlerinin değiştirilmesi için gereken düzenlemeleri yapalım. Bunun için öncelikle hücreleri yarattığınız yere bir satır daha eklemeniz gerekiyor. Nereye ekleyeceğinizi anlamanız için etrafındaki bir kaç satır ile birlikte veriyorum. Yeni eklediğim satırı koyu yaptım.
if (cell == nil)
{
// Hücre yarat
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Satırlar seçilemesin (Bu satırı silerseniz seçtiğiniz satırlar mavi olur)
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// Satır değiştirme kontrolünü göster
cell.showsReorderControl = YES;
}
Buna ek olarak, yine
UITableViewDataSource protokülünde tanımlanmış olan, satır değişimi ile ilgili metodların implementasyonunu yapmanız gerekiyor. Açıklamlar yine kod içerisinde var. Zaten kodun fazla açıklamaya ihtiyacı olduğunu da düşünmüyorum

.
// Tablonun bize satırın hareket ettirilmesine izin verip vermeyeceğimizi sorduğu metod
- (BOOL)tableView:(UITableView *)tableview canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
// Tablonun bize kullanıcının bir satırı bir yerden başka bir yere taşıdığını haber vermek için kullandığı metod
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
// Satırın eksi ve yeni yerlerini öğren
int eskiSatirNo = [fromIndexPath indexAtPosition:1];
int yeniSatirNo = [toIndexPath indexAtPosition:1];
// Satır değişikliğini diziye de yansıt
id gecici = [dizi objectAtIndex:eskiSatirNo];
[gecici retain];
[dizi removeObjectAtIndex:eskiSatirNo];
[dizi insertObject:gecici atIndex:yeniSatirNo];
}
Bu işlemlerden sonra programı çalıştırısanız, düzenleme modundayken satırları sağ tarafta bulunan ikonlardan tutup sürükleyerek değiştirebilirsiniz.
Yorumlar
Bu yazı hakkında toplam 9 yorum bulunmaktadır.
Siz de yorum ekleyebilirsiniz.
benim gibi yeni başlıyanlar için çok yararlı bilgiler var.yazılar iiçin teşekkürler .iyi çalısmalar herkese
Örneğin kaynak kodu ayrı bir dosya olarak yok kodun tamamını buraya yazmışım zaten.
kaynak kod nerede acaba teşkkürler şimdiden
Siz tableView:cellForRowAtIndexpath: metodu içerisinde doğru satıra doğru resim verdiğiniz sürece bir şey karışmaz. Ancak satırlar üst üste gelebilir o da satır yüksekliğinin ayarlanmamış olmasından kaynaklanır. Satır yüksekliği de UITableViewDelegate protokolünün tableView:heightForRowAtIndexPath: metodu ile ayarlanabilir.
tableview de her satırda resim göstermek istiyorum. Fakat tableview aşağı yukarı kaydırdıkça resimler karışıyor. Farklı satırlarda çıkıyor. Bunu nasıl yapabilirim. Haber siteleri gibi.
gerçekten çok teşekkürler.
Eğer feedURLConnection adlı özelliği otomatik olarak retain yapacak şekilde tanımlamışsanız, aşağıdaki satırda yaptığınız işlemde bu özelliğin referans sayısı 2 kez artırılır.
self.feedURLConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
Bir kez objeyi self. diye kullandığınızdan kendi setter metodu çağrılıp retain yapacağı için, bir kez de siz alloc ettiğiniz için.
Sorunu çözmek için ya ordaki self. sözcüğünü kaldırın, ya property'nin retain özelliğini kaldırın, ya da NSURLConnection sınıfının işinize yarar bir convenience constructor'ı varsa alloc etmek yerine onu kullanın. Daha saçma bir çözüm olarak 2 kere release çağırabilirsiniz aşağıda.
Merhabalar, bu mesajı iletişim bölümünden göndermeye çalıştım lakin bi problem çıktığı için burdan göndermek istedim. ben sakarya üniversitesi bilgisayar müh. bölümü 3. sınıf öğrencisiyim. 4-5 ay kadardır zaman buldukça iphone uygulamalarıyla uğraşıyorum. memory management olayında sürekli sıkıntı yaşıyorum. mesela her ürettiğim nesneyi kesinlikle relase veya autorealse ediyorum. aksatmıyorum. thread gereken yerlerde NSAutoPoolRelease kullanıyorum ama yinede leaks oluşuyor. yabancı kaynakları da inceledim memory management hakkında sadece oluşturduğunuz objeyi release edin diyor. başka da bi detay yok.
-(id) initWithUrl:(NSURL *) FeedURL
{
self = [super init];
if (self)
{
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:FeedURL];
self.feedURLConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[urlRequest release];
[self.feedURLConnection release];
}
return self;
}
mesela böyle bir init metodum var. init esnasında download edilecek url'i alıyorum. sadece 2 obje oluşturuyorum ve release ediyorum. ona rağmen leak çıkıyor. eğer müsait olduğunuz bir zamanda yardımcı olabilirseniz gerçekten çok sevinirim. şimdiden teşekkürler. iyi çalışmalar.
elinize sağlık.
Yorum Yazın