Bu yazımda çok basit bir iPhone uygulamasının nasıl yazılacağını
anlatacağım. Göstereceğim örnek uygulamanın yapacağı tek şey aynı daha
önce yazdığım Android ile ilgili yazıda olduğu gibi, ekranda bir tuş
gösterip, tuşa basıldığında kullanıcıya bir mesaj göstermek. Dolayısı
ile bu yazının, Android için yazdığım öteki yazının iPhone
versiyonu olduğunu söyleyebilirim. Ancak burada anlatmam gereken daha
fazla şey olacak çünkü her ne kadar iOS Android'den çok daha iyi ve
programcı dostu bir işletim sistemi olsa da, daha önce Mac OSX için
yazılım geliştirmemiş olan kişilere tamamen Fransız gelecek bir ortam.
Bunun iki temel sebebi var. Biri iPhone uygulamaları geliştirirken
Windows veya Linux kullanıcılarının tamamen yabancıolduğu Objective-C
dilini kullanmak zorunda olmak. Diğeri de yazılım geliştirme ortamı
olarak Visual Studio ve Eclipse'ten çok farklı bir şekilde çalışan
XCode IDE'sinin kullanılması.
Göstereğim uygulamanın kendi bir pek işe yarar bir şey yapmıyor belki
ancak iOS ortamına giriş yapmak için yeterli olduğunu düşünüyorum. Bu
yazımda objective-c dilini anlatmak gibi bir amacım yok, ancak yine de
yeri geldiğinde çok kullanılan bazı yapıların ne anlama geldiği hakkında
kısa açıklamalar yapacağım. Bu yazıyı okuduktan sonra aşağıdaki
soruların cevaplarını almış olacaksınız.
- iPhone uygulamaları geliştirmek için hangi yazılım ve donanıma ihtiyaç vardır?
- XCode ile bir iPhone projesi nasıl oluşturulur?
- Bir iPhone projesi hangi klasör ve dosyaları içerir ve bunların işlevi nedir?
- Interface Builder kullanılarak nasıl arayüz tasarlanır?
- Arayüz ile kod arasında nasıl bağlantı kurulur?
- Tuşa basmak gibi basit olaylar nasıl karşılanır?
- Kullanıcıya bir mesaj en kolay nasıl gösterilir?
- iPhone simülatörü nasıl kullanılır?
-
Bu cevaplar, iPhone programlama ile ilgili Türkçe bilginin neredeyse hiç
olmadığı bu zamanda iPhone uygulamaları geliştirmeye başlangıç yapmak
için yeterli olacaktır. Eğer vakit bulabilirsem gelecekte farklı arayüz bileşenlerinin nasıl kullanıldıklarını, cihaz içerisine nasıl kalıcı veriler tutulacağını ve ivme sensörü, GPS, pusula gibi donanımların nasıl kullanılacağını örnekler ile gösteren yazılar yazmayı planlıyorum.
iPhone Uygulamaları Geliştirmek İçin İhtiyacınız Olan Şeyler
Her şeyden önce bir Mac OSX işletim sistemine ihtiyacınız var. Bu gerçek bir Mac donanımı üzerinde çalışmak zorunda değil, sanal bir makinede çalışıyor da olabilir. Mac'i olmayanlara tavsiyem, bedava olarak indirebilecekleri Virtual Box üzerine OSX kurmaları. İnternette bunun nasıl yapılacağı ile ilgili bol miktarda kaynak mevcut o yüzden burada ona değinmeyeceğim ancak basit ve sorunsuz bir süreç değil onu söyleyeyim. Windows üzerinde geliştirmenin bir yolu yok mu diye aramaya kasmayın, yok.
Çalışan bir OSX'e sahip olduktan sonra yapmanız gereken şey AppStore'dan XCode'u indirip kurmak. XCode kurulduktan sonra gerekli SDK'ları kendisi çekiyor.
Eğer yazdığınız programın sadece simülatörde çalışması sizin için yeterliyse, başka bir şeye ihtiyacınız yok. Ancak kendi cihazınızda da çalışmasını istiyorsanız, ya da AppStore'a çıkarmak istiyorsanız ne yazık ki 99$ bayılıp, Apple Developer Program'a kayıt olmanız gerekli. Eğer cihazınıza jailbreak yaptıysanız, programa kayıt olmadan kendi cihazınızda da çalıştırabilirsiniz ancak bunun nasıl yapılacağını da burdan göstermeyeceğim çünkü internette kolaylıkla bulabilirsiniz. Bu yazıyı takip etmek için simülatörü kullanabiliyor olmanız yeterli çünkü simülatör işini gerçekten çok iyi yapıyor.
Önce Biraz Terminoloji
iPhone SDK ile yazılım geliştirirken kullandığımız framework'un adı Cocoa Touch. Bu framework kendi içerisinde bir çok farklı framework'ü barındırıyor. Bunlardan en önemlisi tüm arayüz bileşenlerini ve bunları kontrol etmemizi sağlayan sınıfları içeren UIKit. Bu Framework MVC adı verilen design pattern kullanılarak tasarlanmış. Kullanacağımız tüm arayüz bileşenleri View adındaki bir sınıftan türemiş. Yani basit bir tuş da bir view, tablo da, tüm bir ekran da. Bu view'leri kontrol etmek amacıyla da ViewController adında bir sınıf tanımlanmış. Bizim yerimize tonla şeyi halledip işimizi kolaylaştıran bu sınıflardan bol miktarda kullanacağız. Genelde her ekran ve ekranın içerdiği tüm bileşenler için tek ViewController kullanılıyor. Yani bir ViewController ile birden fazla view kontrol edilebiliyor. Bu konuda daha detaylı bilgi edinmek isterseniz, internette MVC ile ilgili bir çok kaynak bulabilirsiniz.
iPhone yazılımları geliştirirken bilinmesi gereken bir diğer nokta ise bellek yönetim mekanizması. Objective-C ile yazılan bu programlarda bellek, reference-counting mekanizması ile yönetiliyor. Her nesne ilk yaratıldığında referans sayısı 1 iken, objeyi her kullanan bu değeri 1 artırıyor, işi bittiğinde de 1 azaltıyor. Referans sayısı 0'a inen nesneler artık kimse tarafından kullanılmadıkları için bellekten siliniyor. Referans sayısını artırıp azaltma işlemi Objective-C'nin retain ve release metodlarıyla yapılıyor.
Yeni Bir iPhone Projesi Oluşturulması
Öncelikle XCode'u açıp ve yukarıdaki menüden File >> New Project seçeneğini seçiyoruz ve karşımıza aşağıdaki şekilde gösterilen pencere geliyor.
P
encerenin sol kısmında iOS ve MacOSX olmak üzere 2 bölme var, çünkü her iki platforma da aynı araçları kullanarak yazılım geliştiriliyor. Bizi iPhone uygulaması geliştireceğimiz için, sol taraftan iOS - Application seçeneğini seçiyoruz. Bu işlemi yaptıktan sonra sağ tarafta bir sürü seçenek görülecektir. Bunlardan en temel olanı herhangi bir ekran içermeyen boş bir proje yaratan Window-based Application. En sık kullanacağımız ise tek bir View ve ViewController içeren bir proje yaratan View-based Application. Bu yazıdaki uygulama kontrol edilmesi gereken tek ekranı olduğu için tek bir ViewController içerecek. Arayüzü tasarlarken ekranı temsil eden view'in içine child view'ler ekleyeceğiz. Bu child view'ler de yine ekranı kontrol eden ViewController tarafından kontrol edilecek. Bu yüzden View-based Application taslağını seçiyor ve alt kısımda da iPhone'u seçili bırakarak sağ alt kısımdaki Choose tuşuna basıyoruz. Ardından açılan ekrandan da projeyi yaratacağımız yeri seçip onayladıktan sonra projemiz yaratılmış oluyor. Şimdi aşağıdaki resimde görülen projenin içerdiği dosyaların işlevleri neler ondan bahsedeyim:
OrnekAppDelegate.h: Uygulamanın genelinde kullanılacak olan değişkenlerin tanımlamalarını içeren, bu tanımlamaları uygulamanın içerdiği View ya da ViewController'lara iletilmesini sağlayan header dosyası.
OrnekAppDelegate.m: Uygulamanın açılma işleminin başladığı sınıfın kodunu içeren dosya. Bu sınıftan bir nesne main.m dosyasında türetilir.
OrnekViewController.h ve OrnekViewController.m: Uygulamanın herhangi bir ekranını (bu örnekte zaten tek ekran var) kontrol edecek, ViewController sınıfından türemiş olan, OrnekViewController sınıfına ait tanımlamaları içeren header ve kod dosyası.
Ornek_Prefix.pch: Pre-compiled header dosyası. Bu dosya ile pek bir işiniz yok.
main.m: Diğer arayüzlü program yazdığımız ortamlarda olduğu gibi uygulamanın ihtiyacı olan nesneleri yaratıp programın çalışmasını başlatan kod dosyası.
OrnekViewController.xib: Uygulamanın içerdiği ekranın tasarımı ile ilgili bilgiler içeren Interface Builder dosyası. Arayüz tasarımı işini bu dosyayı Interface Builder ile değiştirerek yapacağız.
MainWindow.xib: Ana pencerenin tasarımını içeren Interface Builder dosyası.
Ornek-Info.plist: Uygulama ile ilgili key-value şeklinde tutulmuş bilgiler içeren dosya. Bu dosya ile şimdilik işimiz yok ancak gelecekte olacak.
Projeyi şu anki hali ile simülatörde denemek için yapmamız gereken tek şey editör penceresinin üst kısmında bulunan ve aşağıdaki şekilde göstermiş olduğum Build and Run tuşuna basmak.
Bu tuşa bastıktan sonra eğer açık değilse iPhone simülatörü açılacak ve uygulamamız içerisine yüklenerek çalıştırılacaktır. Uygulamanın şu anki haliyle boş bir ekran çıkarmaktan başka bir şey yapmadığını gördükten sonra, Build and Run tuşunun sağ tarafındaki kırmızı Stop tuşuna basarak durduruyoruz.
iPhone simülatörü, normal iPhone, iPhone4 (retina display) ve iPad cihazlarını simüle edebilmekte. Ben aksini söylemedikçe bu blog'ta gördüğünüz tüm kodları normal iPhone simülatörü üzerinde denemelisiniz. Çünkü bazı durumlarda (bu uygulamada değil) uygulamanın iPhone4'te de aynı şekilde görünmesi için ek işlemler yapmak gerekiyor ve bu daha ileride değineceğim bir konu. Dediğimi yapmak için simülatör penceresini öne getirip yukarıdaki menüden Hardware >> Device >> iPhone seçeneğini seçin. Bunu simülatörü her kapatıp açışınızdan sonra tekrar yapmanız gerekiyor. Bu yüzen XCode ile işiniz bitene kadar simülatörü kapatmanızı tavsiye etmem. Zaten siz yazdığınız uygulamayı her çalıştırmaya kalktığınızda simülatöre uygulamanın en son hali yüklenip çalıştırılıyor o yüzden kapatmanıza gerek yok.
Programın Arayüzünün Tasarlanması
Sıra uygulamamızı yazmaya geldi. Kod yazmadan önce arayüzü tasarlamak daha mantıklı bir hareket olduğu için, öncelikle XCode'un sol kısmındaki panelden OrnekViewController.xib adlı dosyayı çift tıklayarak Interface Builder'da açıyoruz. Interface Builder birden fazla pencere içeren, garip görünümlü bir arayüz editörü. Aşağıdaki resimde kullanacağımız tüm pencerelerini açık halde görebilirsiniz.
Bu pencerelerden en soldaki, arayüze koymak istediğimiz komponentleri bulabileceğimiz Library penceresi. Sağdan ikinci pencere açmış olduğumuz .xib dosyasının içeriğini gösteriyor. Eğer o penceredeki View objesine çift tıklarsak hemen solunda gördüğünüz boş arayüzü içeren pencere açılır. En sağdaki pencere ise seçili obje ile ilgili özellikleri görüp değiştirebileceğimiz Inspector penceresi. Bu pencerenin en üst kısmında 4 adet tab var. Bunlardan ilki (Attributes) seçili bileşenin kendine has özelliklerini değiştirmeye yarıyor. İkincisi (Connections), bileşenin sahip olduğu eventlerin hangi metodlar tarafından karşılanacağını ayalamamızı sağlıyor. Cetvelle gösterilmiş olan üçüncü tab (Size), bileşen(ler)in boyut ve yerini ayarlamaya yarıyor. Son tab ise ise bileşenin sahip olduğu sınıf ile ilgili değişikler yapmamıza yarıyor. Şimdilik bu son tab ile işimiz yok. İşleyiş diğer IDE'lere benzer şekilde. Kütüphaneden istediğimiz bileşeni view penceresine sürükleyip bırakıyoruz ve daha sonra da istediğimiz özelliklerini Inspector penceresinden değiştiriyoruz. Yazılarımı gereksiz yere uzatmamak için Inspector penceresinden bir şeyi değiştirdiğimizi söylerken hangi tabı kasdettiğimi söylemeyeceğim. Zaten hangisinde olacağı söylediğim şeyden rahatlıkla anlaşılabilir. Boyut/Yer değiştirme bölmesindeki seçenekleri de kendiniz deneyip bulabilirsiniz zaten, o yüzden onların nasıl çalıştığını da söylemeyeceğim.
Bu uygulama için ihtiyacımız olan şey, kullanıcının ismini girmesini sağlayacak bir yazı kutusu ve kullanıcı basınca bir mesaj gösterecek olan bir tuş. Bunun için kütüphaneden view penceresinin içerisine Label, Text Field ve Round Rect Button bileşenlerinden birer tane sürüklüyoruz. Label'ın Text özelliğini "Adın ne?" olarak, tuşun Title özelliğini ise "Bas bakalım!" olarak değiştiriyoruz. Daha sonra bileşenlerin boyutlarını ve yerlerini ister üzerlerinden veya kenarlarından tutup sürükleyerek, ister Inspector penceresinden değiştirerek aşağıdaki hale getiriyoruz.
Arayüzü kaydedip XCode'a dönüyoruz. Şimdi yapmamız gereken ilk şey arayüze koyduğumuz bileşenlerden hangilerine kod içerisinden erişmemiz gerekeceğini bulmak çünkü onlar için Outlet tanımlamamız gerekiyor. Bu uygulamada sadece yazı kutusuna erişmemiz gerekiyor çünkü kullanıcıya göstereceğimiz mesajı oluştururken bu kutu içerisine yazılmış olan ismi kullanacağız. Tuşa kod içerisinden erişmemize gerek yok çünkü onun herhangi bir özelliğini değiştirmeyeceğiz. Tuş sadece basıldığında yazmış olduğumuz bir metodu çağıracak.
OrnekViewController.h adlı header dosyasını açıp aşağıdaki hale getiriyoruz.
#import <UIKit/UIKit.h>
@interface OrnekViewController : UIViewController {
}
@property (nonatomic, retain) IBOutlet UITextField* tv;
-(IBAction)tusaBasildi;
@end
Burada koda 2 yeni satır ekledik. Birincisi OrnekViewController sınıfı için UITextField türünden bir Outlet tanımlıyor. Outlet olarak tanımladığımız değişkenler her zaman işaretçi (pointer) olmalıdırlar. Çünkü bu değişkenler Interface Builder içerisinden bağlandıkları arayüz bileşenine işaret ederler. Parantez içerisindeki nonatomic ve retain sözcükleri, derleyicinin @property olarak tanımlanmış değişkenler için otomatik olarak oluşturacağı getter ve setter metodlarının nasıl işleyeceğini berlirliyor. Söz konusu değişken birden fazla thread tarafından kullanılmayacaksa nonatomic kullanmak daha verimli. Retain kelimesi ise o değişkene bir atama yapıldığında, eskiden işaret ettiği nesnenin referans sayısının bir azaltılıp, yeni işaret etmeye başladığı nesnenin referans sayısını bir artırma işleminin setter metodu tarafından otomatik olarak yapılmasını istediğimizi belirtiyor. Bu cümleden bir şey anlamadıysanız internette "reference counting" diye arama yapın, çünkü iPhone uygulamaları yazarken bellek yönetimiyle ilgili problemler yaşamamak için bu mekanizmayı iyi öğrenmeniz şart.
Koda eklediğimiz diğer satır ise tuşa bastığımızda çağrılacak olan metodunun prototipi. Burada IBAction yerine void de kullanabilirdik ancak bu durumda Interface Builder metodu görmeyeceği için metod ile event arasındaki bağlantıyı kod içerisinden yapmamız gerekirdi. Bu metodun çağrılması için Interface Builder'da tuş ile bu metod arasında bağlantı kurmamız gerekiyor. Bunun nasıl yapılacağını biraz ileride anlatacağım.
Kodlama kısmında yapmamız gereken bir diğer işlem OrnekViewController.m adlı kod dosyayı açıp, header dosyasında yaptığımız tanımlamaların implementasyonlarını yapmak.
#import "OrnekViewController.h"
@implementation OrnekViewController
@synthesize tv;
-(IBAction)tusaBasildi
{
NSString* isim = tv.text;
NSString* msg = [NSString stringWithFormat:@"Merhaba %@", isim];
UIAlertView* alert = [[UIAlertView alloc] initWithTitle: nil message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
- (void)viewDidUnload
{
self.tv = nil;
}
- (void)dealloc
{
[tv release];
[super dealloc];
}
@end
Dikkat ederseniz bu kodun proje yaratıldığında ilk halinden daha kısa olduğunu görürsünüz. Bunun sebebi bu uygulamada işimize yaramayacak olan, derleyicinin belki kullanırız diye bizim için yaratmış olduğu metod implementasyonlarını silmiş olmam. Eklediklerime gelirsek:
@synthesize sözcüğü ile, öteki dosyada tanımlamış olduğumuz Outlet'in bu dosya içerisinden de görülmesini ve bu Outlet için setter ve getter metodlarının yaratılmasını sağladık.
"tusaBasildi" adlı metodun içerisinde, Outlet aracılığı ile yazı kutusuna girilmiş olan ismi de kullanarak bir mesaj oluşturduk. Daha sonra da bir UIAlertView nesnesi yaratıp ekranda gösterdik. Gösterdikten sonra da bellekten silinmesi için alloc metodu ile yaratırken 1 yapmış olduğumuz referans sayısını release metodu ile 1 azalttık.
"viewDidUnload" ve "dealloc" metodlarında Outlet'in işaret ettiği nesnenin ekran kapandıktan sonra bellekte kalmaması için referans sayılarını azalttık. Tek ekranlı bir programda bunu yapmak zorunda değiliz çünkü ekran kapandı mı program da kapandı demektir ancak çok ekranlı ir programda ekranlar arasındaki geçişlerde memory leak yapmamak için bunu yapmaya alışmak gerekiyor.
Şimdi kodu çalıştırmadan önce yarattığımız Outlet'i TextView'a, tusaBasildi metodunu ise ekrandaki tuşun onTouchUpInside event'ine bağlamamız gerekiyor. Bunu yapmak için kodda yaptığımız değişiklikleri kaydedip, OrnekViewController.xib dosyasını tekrar Interface Builder'da açıyoruz. Outleti bağlama işlemini yapmak için fareyi, aşağıdaki şekilde görüldüğü gibi .xib dosyasının içeriğini gösteren penceredeki File's Owner nesnesinden, arayüzdeki TextField'a kadar kontrol tuşuna basılı tutarak sürükleyip bırakıyoruz. Bıraktıktan sonra açılan popup menüden tv seçeneğini (yaratmış olduğumuz Outlet'in adını) seçiyoruz. Buna alternatif olarak File's Owner'ı seçip, Inspector penceresindeki Connections panelinden tv outletini bulup, oradan TextField üzerine sürükle bırak yapabilirdik.
Tuşa basıldığında yazmış olduğumuz metodun çağrılması için önce tuşumuzu seçiyoruz. Daha sonra da aşağıdaki şekilde görüldüü gibi faremizi, Connections panelindeki event listesindeki "Touch Up Inside" event'inden File's Owner ikonuna sürükleyip bırakıyor ve açılan popup menüden "tusaBasildi" seçeneğini seçiyoruz.
Bu işlemlerden sonra değişiklikleri kaydedip, programı çalıştırırsak aşağıda gösterildiği gibi kullanıcı ismini yazıp tuşa bastığında mesaj gösteren bir uygulama görmemiz gerekiyor. Eğer siz görmüyorsanız bir şeyleri yanlış yapmışsınız demektir.
Ancak bu programın ufak bir problemi var. Klavyeyi kapatmanın bir yolu yok
. Bu sorunu çözmek için iPhone'a TextField ile işimiz bittiğinde klavyenin ekrandan kaldırılabileceğini söylememiz gerekiyor. Bunu yapmanın birden çok yolu var, ancak ben burada en basitini göstereceğim. Göstermeden önce bu tip şeyleri nereden öğrenebileceğini söyleyeyim. Tabi ki iPhone SDK dökümantasyonundan. Eğer şu adresten UITextField sınıfının dökümantasyonuna bakarsanız, UITextFieldDelegate adlı bir protokolü desteklediğini görürsünüz. Bu protokolün aşağıda göstermiş olduğum metodunu ViewController sınıfı içerisinde aşağıdaki şekilde implement edersek, klavyedeki return tuşuna bastığımızda klavye kapanacaktır.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return NO;
}
Oldukça uzun bir yazı oldu, umarım yararlı olmuştur. Fırsat buldukça mobil uygulamlar ve özellikle de iPhone programlama ile ilgili işe yarar bilgiler içeren yazılar yazmaya devam edeceğim.