Şu ana kadar yazdığım yazılarda iPhone/iPad uygulamaları için arayüz
tasarımı yaparken kullanılan temel bileşenler ve ekranlar arasında
navigasyon konusunda gerekli olan temel bilgileri verdim. Bundan
sonrasında örnek uygulamadan çok belli başlı işlemleri yapan kod
parçaları göstereceğim. Bu yazıda göstereceklerim dosya yönetimi ile
ilgili. Daha spesifik olmak gerekirse, iPhone SDK içerisindeki metodları
kullanarak Application Bundle içerisindeki bir dosyayı üzerinde
değişiklik yapabileceğiniz bir yere nasıl kopyalarsınız, dosya ve klasör
nasıl yaratır, taşır, yeniden adlandırır ya da silersiniz, yarattığınız
veya kopyaladığınız dosyalara nasıl erişirsiniz bunları anlatacağım.
Yazdığınız iPhone uygulamasını cihaza veya simülatöre yüklendiğinizde
iOS uygulamanız için sadece o uygulamanın erişebileceği özel bir alan
yaratıyor. Bu alan içerisinde uygulamanızın kendisini ve uygulamayla
birlikte verdiğiniz dosyaları içeren Application Bundle konuluyor.
Daha sonra uygulamanız çalışırken bu bundle içerisinden istediği
verileri okuyabiliyor ancak değişiklik yapamıyor (Aslında yapmanın yolu
var ancak kesinlikle tavsiye edilmiyor). Uygulamanın üzerinde değişiklik
yapacağı dosyaları koymanız için iOS tarafından önceden tanımlanmış
bazı klasörler var. Bunlardan en önemli 2 tanesi Documents ve Library
klasörleri. Bu klasörler de uygulamaya özel. Yani her uygulamanın ayrı Documents ve Library klasörleri var ve buralara sadece kendisi erişebiliyor.
Diyelim ki uygulamanız ile birlikte bir .txt dosyası verdiniz. Uygulamanızın bu dosya üzerinde sonradan değişiklik yapabilmesini istiyorsanuz, uygulamanızın ilk çalıştığında bu dosyayı Bundle'dan Documents ya da Library klasörüne kopyalaması ve daha sonra da hep oradaki dosyayı kullanması gerekiyor. Bu iş için genelde Documents klasörü kullanılmakta ancak bazı durumlarda, mesela uygulamanız "iTunes File Sharing" destekliyorsa, kullanıcının görmesini istemediğiniz dosyaları Library klasörüne koymak zorundasınız. Ancak bu özelliğin ne olduğunu henüz bilmediğiniz için siz hep Documents klasörünü kullanacakmışız gibi düşünün.
Kopyalama işlemini yapabilmek için öncelikle orjinal dosyanın ve kopyalanacağı yerin (Documents klasörünün) yolunu elde etmeniz gerekiyor. Kopyalayacağınız dosyanın isminin "deneme.txt" olduğunu, XCode projenize eklenmiş olduğunu ve dolayısıyla paketlenmiş uygulamanın Bundle'ı içerisinde bulunacağını varsayalım. Bundle içerisindeki dosyanın yolunu şu şekilde alabilirsiniz.
NSString* kaynakYolu = [[NSBundle mainBundle] pathForResource:@"deneme" ofType:@"txt"];
Şimdi sıra geldi Documents klasörünün yolunu bulup sonuna deneme.txt ekleyerek hedef yolu oluşturmaya. Bunun için yine özel bir metod kullanmanız gerekiyor çünkü bu yol her kullanıcı için farklılık göstermekte.
NSArray* yollar = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsYolu = [yollar objectAtIndex:0];
NSString* hedefYolu = [documentsYolu stringByAppendingPathComponent:@"deneme.txt"];
Farkettiyseniz burada gördüğünüz NSSearchPathForDirectoriesInDomains() metodu Objective-C sentaksı ile çağrılmamış, çünkü bir Objective-C metodu değil, C metodu. Bu yüzden de normal C sentaksı ile, yani parantezlerle çağrılması gerekiyor. Bu metodun ilk parametresini NSLibraryDirectory olarak verseydik o zaman metod bize Library klasörünün yolunu döndürecekti. Dikkat ederseniz metod bize bir String değil, dizi döndürüyor. Bu dizi verdiğiniz parametrelere uygun olan tüm yolları içeriyor. Ancak bu örnekte olduğu gibi belirli bir yeri istediğinizde doğrudan o dizinin ilk elemanını alıp kullanabilirsiniz. Metodun diğer parametrelerini şimdilik boşverin çünkü onlara nerdeyse her zaman bu değerleri vereceksiniz. Klasör yolunun sonuna dosya adını doğrudan NSString sınıfının metodlarını kullanarak da ekleyebilirdim ancak stringByAppendingPathComponent: metodunu kullanmak String'lerin sonlarında slash olup olmamasından bağımsız olarak doğru işlem yapılmasını garantilediği için daha güvenilir.
Şimdi yolları elde ettiğimize göre kopyalama işlemini yapabiliriz. Önce kopyalama işleminin sadece bir kez yapıldığından emin olmak için hedef yolunda öyle bir dosya zaten var mı diye kontrol edeceğiz, yoksa kopyalayacağız. Bunu da şu şekilde yapıyoruz.
NSError* err;
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) // Dosya orada zaten var mi kontrol et
{
[[NSFileManager defaultManager] copyItemAtPath:kaynakYolu toPath:hedefYolu error:&err];
// Kopyalama islemi sirasında hata olusmussa konsola yazdir
if (error)
NSLog(@"%@",[err localizedDescription]);
}
Burada hem dosya var mı yok mu diye kontrol etmek işlemini, hem de kopyalama işlemini NSFileManager türünden bir singleton olan defaultManager nesnesinin metodları ile yaptık. Kopyalama işlemini yapan metodun ikinci parametresi olarak NSError türünden bir nesne verdiğime dikkat edin. Metod hata olması durumunda bu nesneyi yaratıp için doldurmakta. Dolayısıyla nesneye işaret eden işaretçinin değerinin nil olup olmadığına bakarak kopyalama işleminin başarıyla tamamlanıp tamamlanmadığını anlamamak mümkün. Burada hata oluşması durumunda hatanın ne olduğunu NSLog metodu ile konsola yazdırdım. Normalde tabi ki bundan fazlasını yapmanız gerekecektir. Eğer hata kontrolü istemiyorsanız bu parametreye direk nil değerini geçebilirsiniz.
Bu kopyalama işlemini yapmanın en mantıklı yeri Application delegate'in uygulama her çalıştırıldığında çağrılan şu metod:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
}
Yol oluşturma ve kopyalama işlemini detaylı olarak gösterdikten sonra, yapma ihtiyacı duyabileceğiniz diğer dosya işlemlerini kısaca göstereyim.
// Dosya yaratma
NSData* veri; // Bunun bir sekilde elinizde oldugunu varsayin
[[NSFileManager defaultManager] createFileAtPath:yol contents:veri attributes:nil];
// Dosya/klasor tasima veya yeniden adlandirma
[[NSFileManager defaultManager] moveItemAtToPath:kaynakYolu toPath:hedefYolu error:&err];
// Dosya/klasor silme
[[NSFileManager defaultManager] removeItemAtPath:yol error:&err];
Burada değinmem gereken tek nokta dosya yaratmak için elinizde NSData türünden bir nesne bulunmasının gerekiyor olması. Bunu elde etmenin bir sürü yolu var. Bunların bir çoğu NSData sınıfının initWith ile başlayan metodlarını kullanmaktan ibaret. Ayrıca dosya yaratmak için tek yol bu da değil. NSString, NSArray gibi sınıflara sahip olan nesnelerin içeriklerini writeToFile:atomically metodunu kullanarak doğrudan bir dosyaya yazabilirsiniz.
Yazımı bitirmeden önce son olarak burada bahsettiğim tüm metodların bir de Path kelimesinin URL kelimesi ile değiştirilmiş olan versiyonları olduğunu söyleyeyim. Bu metodlar da yolları NSString olarak değil NSURL olarak alıyor. Elinizde NSString değil NSURL türünden nesneler olduğu durumlarda bu metodları kullanmak daha kolayınıza gelebilir.