2016-02-17 13 views
10

iOS uygulamam için bir sunucu arka uç olarak CloudKit kullanıyorum. Bir avuç görüntü (CKAsset) ile birlikte nispeten durağan bir veriyi barındırmak için kullanıyorum. Bu varlıkları halka açık veritabanından almam için zaman geldiğinde bir sorunla karşılaştım. Aşırı yavaş bir hızda yüklerler.CloudKit'ten CKAsset Görüntüsü Getirme Çok Yavaş

Kullanım durumum, görüntüyü koleksiyon görünümünün içindeki her hücreye yüklemek. Görüntüler yalnızca 200 kb boyutundadır, ancak getirme işleminin görüntüyü bir hücrede tamamlaması ve görüntülemesi için ortalama 2,2 saniyedir. Karşılaştırma için, benzer boyutlu stok görüntülerin URL'lerini aldım ve bunları NSURLSession kullanarak yükledim. Her bir resmin yüklenmesi sadece 0,18 - 0,25 saniye sürdü.

Görüntüleri CK'dan indirmenin farklı yollarını denedim: doğrudan kayıt, sorgu ve işlem sorgusu getirme. Hepsinin benzer sonuçları var. Ayrıca, hücre için görüntüyü ayarlamadan önce tamamlama bloğu içindeki ana sıraya geri gönderim.

Veritabanım, çeşitli veri alanlarına sahip birincil nesneye sahip olacak şekilde ayarlanmıştır. Daha sonra her fotoğrafın sadece bir ana nesneye referansı olduğu, fotoğraflar için geriye dönük referans stili sistemi kuruyorum. Bu sayede fotoğrafları ana verilere bürünmeden talep üzerine yükleyebilirim.

Bu şuna benzer:

İlköğretim Nesne: title: String, startDate: Date

Fotoğraf Nesne: Burada owner: String(reference to primary object), image: Asset

doğrudan birini almaya çalıştı örnek isteğidir fotoğraflar:

let publicDb = CKContainer.defaultContainer().publicCloudDatabase 
let configRecordId = CKRecordID(recordName: "e783f542-ec0f-46j4-9e99-b3e3ez505adf") 

publicDb.fetchRecordWithID(configRecordId) { (record, error) -> Void in 
    dispatch_async(dispatch_get_main_queue()) { 
     guard let photoRecord = record else { return } 
     guard let asset = photoRecord["image"] as? CKAsset else { return } 

     guard let photo = NSData(contentsOfURL: asset.fileURL) else { return } 

     let image = UIImage(data: photo)! 

     cell.cardImageView.image = image 
    } 
} 

Bu görüntü indirme işlemlerinin neden bu kadar uzun sürdüğünü anlayamıyorum, ancak makul bir süre içinde yükleyemedikleri takdirde gerçekten çok iyi bir showtopper.

Güncelleme: Daha küçük bir resim olan 23kb ile getirme işlemini denedim. Getirme daha hızlıydı, 0,3 - 1,1 saniye arasında. Bu daha iyi, ama yine de CloudKit'in sağlayabilmesi gereken şeyle ilgili beklentimi karşılamıyor.

+0

tamamını kayıt alıyorsanız:

queryOperation.qualityOfService = .UserInteractive 

İşte benim tam koddur. Bu kayıtta daha fazla varlık var mı? Onu sadece görüntü alanına sınırlandırabilirsiniz.Bunun yanı sıra, yalnızca ana sıradaki kullanıcı arayüzünü güncellediğiniz son ifadeyi uygulamanız gerekir. –

+0

@EdwinVermeer Varlıktaki kayıt, biri görüntü, diğeri sahibine referansla bir dize değeri olmak üzere iki alana sahiptir. Bu diğer satırları ana sıraya gönderimden çıkarabileceğimi biliyorum, ama hiçbir fark yaratmıyor. Getirin tamamlanma bloğu sonsuza dek sürecek olan şeydir. – Jonathan

+0

Ne tür bir ağ üzerinde test ediyorsunuz? İşlemin önceliğini kontrol etmek isteyebilirsiniz, ayrıca kolaylık yöntemlerini kullanmak yerine kaydı el ile getirmeyi de deneyebilirsiniz. – mattsven

cevap

2

Ana iş parçacığınızı yavaşlatan bir şey var, bu da dispatch_async çağrınızın yakalama bloğunu yürütmede gecikme yaşanmasına neden oluyor. Kodunuzun bu kayıt getirme işlevini birden çok kez paralel olarak çağırması mümkün mü? Bu, NSData'nın (contentOfURL: asset.fileURL) işlemesinin ana iş parçacığını almasına ve birikimli gecikmeleri tetiklemesine neden olur.

Her durumda, yalnızca iyi bir uygulama olarak, görüntüyü NSData ile yüklemek, ana iş parçacığına değil arka planda gerçekleştirilmelidir.

+0

Şu anda bu kodu "cellForItemAtIndexPath:" uygulamasında çalıştırıyorum; bu, birden çok kez çalıştırıldığını gösteriyor. Kullanım durumunun, özellikle NSURLSession ile aynı şeyi istisnai sonuçlarla yapabileceğimden, olduğu kadar yavaşlattığını düşünemiyorum. Bu sadece CloudKit'in nasıl kullanılması gerektiği değil mi? Görüntüleri birincil verilerimden ayırdım, böylece görüntüleri ön tarafa değil, talep üzerine yükleyebilirim. – Jonathan

+0

cellForItemAtIndexPath oldukça öngörülemeyen zamanlar olarak adlandırılabilir ve her zaman ana iş parçacığı üzerinde yürütülür. Eşzamansız veri yükleme işlemini gerçekleştirmek çok güvenli değildir. Ekranınızdaki karışık görüntüyü almadığınıza şaşırdım, çünkü dispatch_async çağrısında yakalanan hücre nesnesi, getirme ve görüntüleme arasındaki gecikme sırasında başka bir öğe için yeniden kullanılma riskini çalıştırıyor. Her neyse, işe almak için bir yol bulmuşsunuz gibi görünüyor, bu yüzden bu soru hakkında daha fazla bilgiye ihtiyacınız olmayacağını tahmin ediyorum. –

4

CKQueryOperation'ı kullanıyorum. Aşağıdaki satırı koduma ekledikten sonra CKAssets'i yaklaşık 5-10 kat artırdığımı fark ettim.

func getReportPhotos(report:Report, completionHandler: (report:Report?, error:NSError?) ->()) { 
    let photo : Photo = report.photos![0] as! Photo 
    let predicate : NSPredicate = NSPredicate(format: "recordID = %@", CKRecordID(recordName: photo.identifier!)) 
    let query : CKQuery = CKQuery(recordType: "Photo", predicate: predicate) 
    let queryOperation : CKQueryOperation = CKQueryOperation() 
    queryOperation.query = query 
    queryOperation.resultsLimit = numberOfReportsPerQuery   
    queryOperation.qualityOfService = .UserInteractive 
    queryOperation.recordFetchedBlock = { record in 
     photo.date = record.objectForKey("date") as? NSDate 
     photo.fileType = record.objectForKey("fileType") as? String 
     let asset : CKAsset? = record.objectForKey("image") as? CKAsset 
     if asset != nil { 
      let photoData : NSData? = NSData(contentsOfURL:asset!.fileURL) 
      let photo : Photo = report.photos![0] as! Photo 
      photo.image = UIImage(data:photoData!) 
     } 

    } 
    queryOperation.queryCompletionBlock = { queryCursor, error in 
     dispatch_async(dispatch_get_main_queue(), { 
      completionHandler(report: report, error: error) 
     }) 
    } 
    publicDatabase?.addOperation(queryOperation) 
} 
+0

Bu değişikliği yaptıktan sonra, yaklaşık 0.1-0.5 saniyede 80k resmi indirebilirsiniz. Verilerinizi CK kontrol panelinin içinde nasıl yapılandırdınız? Hızımı iki katına çıkardı. Kabaca 2.X saniyeden 1.0-1.7 saniyeye indi. – Jonathan

+0

Her biri 90 saniyede 2 saniyeden az, bazen de 1 saniyeden az olan 25 kayıt yüklüyorum, bu yüzden kayıt başına 0.08 saniyeden az. İyi bir WiFi bağlantısındayım, ancak bugün LTE ile çıktığımda test ettim ve sonuçlar benzerdi. Her kaydın 14 dize alanı, bir konum alanı ve tarih alanı ve görüntü verilerini tutan bir varlık alanı vardır. Hala geliştirme modundayım ve tüm arama, sorgulama ve sıralama kontrol ediliyor. –

+0

Bunlar aradığım hız türleri. Yani veri kurulumunuzdaki tüm farklı alanlarla tek bir kayıt var mı? Kurulumumda "Fotoğraf" kaydına referansla birlikte tüm String verilerinin bir kaydı var. Sonra görüntüyü almak istediğimde, sadece bunu doğrudan alabilirim. – Jonathan