Core Data verisini dolu kullanmak – iOS
İlk ve tek ücretli iOS uygulamamız Ebruli Osmanlıca Sözlük’ün son sürümündeki bazı teknik sıkıntılar nedeniyle epey kötü yorum almış bir developer olarak diğer işlerimden vakit ayırıp bu sorunlu versiyonu düzeltmeye karar vermiştim. Yılbaşında bu fırsatı değerlendirip kodu gözden geçirmiş, sorunlu yerlerin civatalarını sıkılaştırmıştım ama istediğim gibi olmamıştı. Araya bir de gâvurların noel tatili girince uygulamayı AppStore’a gönderememiştim.
Bu gece Ebruli’yi kökünden halletmeye karar verdim.
Sorun şuydu: Uygulamanın son versiyonunda Apple’in kendi veritabanı sistemi olan Core Data’yı kullanmak istemiştim. Core-Data’nın kendisi de zaten SQLite tabanlı bir sistem ama kötü bir kod olmasın, abudik gubidik sqlite işlemleri yapmayayım diye bu yolu seçmiştim. Seçmez olaydım!
Uygulamanızı yazarken Core Data modelinizi oluşturabiliyorsunuz fakat ortaya çıkan Sqlite dosyasını doğrudan göremiyorsunuz. Uygulama çalışırken o dosya yoksa otomatik oluşturuluyor. Yani modelinizden sıfırdan üretiliyor. İşte bu noktada bizim Ebruli Sözlük gibi önceden doldurulması gereken 13 bin kelimelik bir veritabanı ihtiyacınız varsa apışıp kalıyorsunuz.
Ebruli Sözlük’ün son sürümünü yazarken bu sorunu çok önemsememiştim. Amele bir yöntemle 13 bin kelimelik csv datası oluşturup projeye dahil etmiş, uygulama ilk açıldığında Core Data verisinin boş olup olmadığına bakıp csv’den veriyi doldurma yoluna gitmiştim. Programcı olarak bana saçma gelmeyen bu işlem maalesef UX (user experience / kullanıcı deneyimi) olarak tam bir rezalet oldu. Çünkü 13 bin satırlık bu veri aktarma süreci iPhone 6 Plus’da bir 2-3 dakika alıyordu. Bu esnada uygulamanın tepesindeki başlık kısmında “İlk kullanım için uygulama ayarlanıyor..” ibaresi koyduğum halde, başlık biraz süslü fontla yazıldığı için kimsenin dikkatini çekmemişti. Aksi gibi bu esnada makine kilitlenmiş gibi davranıyordu. Yine benim cehaletim yüzünden csv aktarma işlemini ayrı bir “thread” içinde yapmayı akıl edememiştim. Bu kadar küfredeceklerini bilsem böyle yapar mıydım.. Bu da yetmezmiş gibi aksilikler ardı arkasına devam ediyormuş meğer.. Csv aktarımı sırasında telefonu kilitlendi sanan kullanıcılar, benim gibi uslu uslu beklemek yerine haklı olarak ekranın sağına soluna dokunup bir interrupt göndermeye çalışıyorlar, o da aktarımın şakadanak sonlanmasına neden oluyormuş. (Bu kısmı tespit edene kadar neler çektim). Ondan sonra AppStore’dan yorum olarak yahut mail yoluyla “Bu ne biçim uygulama, d harfine kadar çalışıyor, gerisi yok.. M harfine kadar çalışıyor gerisi nerde.. 13 bin kelime değil 10 kelime bile yok..” gibi sitem ve ardından veciz sözler şeklinde geri dönüşler aldık..
Bu uygulamanın ilk sürümlerinde de bunun kadar olmasa da talihsizlik vardı.. Onu da kısaca anlatayım ki müstakbel developer arkadaşlara UX dersi olsun..
Eski versiyonunda, doğrudan Sqlite üzerinden veri çekip kullanıcıya sunuyorduk. Bu esnada çok fazla veri çekip hem belleği, hem kullanıcıyı uğraştırmayayım diye her sorguda 10 tane kelime çekiyordum. Yani kullanıcı a’ya bastığında a’yla başlayan binlerce kelimeyi vermek yerine ilk 10 kelimeyi veriyordum. Kullanıcı yazmaya devam ettiğinde filtre daha daraldığı için yine 10 kelime göstererek adamın istediği sonuca bir kaç harf yazarak gitmesini sağlıyordum. Gelen yorum şöyle oldu: “Bu ne biçim sözlük, güya 13 bin kelime var içinde.. A harfinden sadece 10 kelime var.. Hep yalan dolan.. Param haram olsun..”. Tek tek bu kullanıcılara ulaşmaya çalışıp durumu izah ettim. Anlayan bir kaç kullanıcıdan da olumlu yorum yazıp mevzuyu diğerlerine anlatması için ricada bulundum.. AppStore’un bir başka garipliği olarak kendi uygulamama yorum yazamıyorum..
Neyse konuya dönelim..
Yılbaşında uygulamayı revize ederken sadece csv işlemi için ayrı bir thread açtım, böylece aktarım sırasında ekranın sağına soluna dokunulsa da işlem yarıda kalmıyor, bir süre sonra başlıktaki ibare düzelip sözlüğün hazır hale geldiğini bildiriyordu. Fakat bu akşam bu halini de beğenmedim. Yorumları susturmaya yetmez gibi geldi. Ben de geçen sefer okumaya üşendiğim ingilizce blogları iyice kurcalayıp dolu bir Sqlite verisini nasıl Core Data dosyası olarak kullanabileceğimi öğrenmeye çalıştım. Swift versiyonunun yazıldığı şu blogu buldum: http://www.appcoda.com/core-data-preload-sqlite-database/ Burdaki yöntem birebir işimi görmedi, birazcık da başka yerlere baktım: http://pinkstone.co.uk/how-to-remove-wal-files-in-core-data/
Sonra benim gibi ingilizce okumaya üşenen arkadaşlar olabilir diye hem acı tecrübelerimi hem de kısaca bu işin nasıl yapılacağını anlatayım istedim.
Dolu Core Data Verisi Kullanmak
iOS için Xcode uygulamanızı hazırlarken şu göz önünde bulundurulmalı. Projenize ait dosyalar çalışma anında doğrudan kullanılmaz. Proje dosyalarınız “Bundle” klasöründe durur, uygulamanız çalışırken ayrı bir “Data” klasörü söz konusudur. Yani Core Data modelinden üretilen Sqlite dosyası da bu Data klasöründe oluşturulur. Dolayısı ile ne yapıp edip dolu ve CoreData mimarisine uygun sütunlar içeren veritabanı dosyanızı bu “Data” klasörüne kopyalamalısınız.
Adım 1: Dolu Core Data verisini elde edelim
Benim örneğimde uygulamanın mevcut halini çalıştırıp, Csv’den aktarımın düzgün bir şekilde yapıldığına emin olduktan sonra simülatörün ilgili klasörünü bulmak gerekiyor. Çünkü dolu hale gelen Core Data mimarisine göre işlenmiş Sqlite dosyama ancak bu simülatör üzerinden erişebilirim. Klasörün tam adını öğrenmek için şu ifadeyi AppDelegete.m dosyanızda yazıp görebilirsiniz.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSLog(@"%@", [self applicationDocumentsDirectory]); return YES; }
Sonra Mac’inizdeki Finder’i çalıştırıp menüden Go / Go To Folder seçeneğiyle burada gördüğünüz yolu kopyala-yapıştır yapıp ilgili klasörü açabilirsiniz.
Bu klasörde gördüğünüz uzantısı .sqlite olan dosya işte sizin dolu ve Core Data mimarisina göre hazırlanmış dosyanız oluyor. Bunu Xcode Projenize sürükleyip açılan pencerede “Copy item if needed” ve “Add to Targets” seçeneklerini işaretlemeyi unutmayın. Böylece projenize dolu olarak veritabanınızı aktarmış oldunuz.
Adım 2: Uygulamanızın kullanacağı Core Data dosyası ile sizin önceden yerleştirdiğiniz Core Data dosyasını değiştirmek
Yazının ortalarında bahsettiğimiz gibi iOS mimarisinde uygulamamızın içine “bundle” ettiğimiz dosyaların yeri ayrı, çalışma esnasında kullanılan dosyaların yeri ayrıdır. Core Data dosyasının orjinali Data klasöründe yer alır. Uygulama ilk çalıştığında bu data klasöründe Core Data Sqlite dosyası yoksa projenizdeki Core Data model dosyasını baz alan otomatik olarak bir Sqlite dosyası oluşturulur. İşte biz bu işlemi engellemek için “bundle” ettiğimiz kendi dolu Core Data Sqlite dosyamızı uygulama açılır açılmaz bu klasöre kopyalayacağız ve iOS’u şaşırtacağız. Hali hazırda dosyanın var olduğunu anlayan iOS sıfırdan yeni bir Core Data dosya oluşturmayacak böylece..
Bu işlemi yapmak için AppDelegete.m dosyasındaki Core Data fonksiyonlarının olduğu kısımda
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
fonksiyonunun içerisindeki
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
ifadesinin hemen üzerinde şu ifadeleri eklemek gerekiyor:
//Bu ifade zaten var _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; // Bu kısmı biz ekliyoruz.. if(![[NSFileManager defaultManager] fileExistsAtPath:storeURL.path]) { NSError *error = nil; [[NSFileManager defaultManager] copyItemAtURL:[[NSBundle mainBundle] URLForResource:@"Veritabani" withExtension:@"sqlite"] toURL:[self.applicationDocumentsDirectory URLByAppendingPathComponent:@"Veritabani.sqlite"] error:&error]; } //Ekleyecegimiz kısım sona erdi if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
İşte bu kadar. Artık uygulamamız çalıştığında bu kısım imdada yetişip bizim bundle ettiğimiz dosyayı olması gereken yere kopyalayacak ve hiç bir gecikme olmadan uygulamamızda Core Data’nın nimetlerinden faydalanmaya başlayabileceğiz.
Bu kadarcık bir kod yüzünden yediğim lafların haddi hesabı yok maalesef..
Ben yandım eller yanmasın..
[…] önceki blog yazımda mevzuyu uzuun uzun inceleyerek başka developer arkadaşlar aynı hataya düşmesin diye yeni […]
öncelikle çok iyi bir paylaşım kardeşim teşekkür ederim… küçük bi problemim var ben dolu bi veritabanı kullanacağım..program esnasında veri girdi, çıktı veya silme gibi işlemler olmayacak.. bu durumda yaklaşık (yani sözlük gibi )3000 veriyi veritabanına oluşturmam lazım, bunu veri tabanına veri girmemi sağlayan bi program yazıp tek tek mi girmem gerekiyor.. bu veritabanını kolay şekilde oluşturmamın bi yolu varmı..nasıl bi yaklaşım önerirsin.. yazmak istediğim program sadece dolu bi veri tabanını kullanacak..(rusca sözlük..) yardımcı olursan sevinirim kardeşim..
Aslında yazıda tam da bunu anlatıyorum 🙂 Dolu bir veritabanı bir defaya mahsus çalışma esnasında simülatörle oluşturmak ve sonrasında o veritabanını uygulamada kullanmak gerek.
Sözlük kelimelerini csv gibi bir formata aktarıp iOS programınızda yazacağınız ve bir defaya mahsus kullanacağınız bir kod yazıp CSV’yi core-data’ya aktarın. Sonra yazıda anlattığımız şekilde o dolu veritabanı dosyasını bulup projenize yeniden ekleyin ve CSV aktarma kodunu silip doğrudan bu veritabanını kullanın. Kolay gelsin.
çok teşekkürler dostum eyvallah… çok işime yaradı..saolasın..
kardeş bi sorum daha olacak.. ben programı swift 3 ile yazıyorum…csv dosyasından verileri aktarmak yerine, anlattığın gibi veritabanı dosyasına erişip dosyaya bir database editor programıyla
verileri girsem (bunu simulatorde denediğimde veriler normal şekilde çalışıyor) bu veritabanı dosyasını açılışta söylediğin gibi yüklesem bi sorun olurmu sence…paketlemede dağıtımda ..