मैं एक ऐसे ऐप में UICollectionView
का उपयोग कर रहा हूं जो बहुत सारी तस्वीरें (50-200) प्रदर्शित कर रहा है और मुझे इसे स्नैपी होने में समस्याएं आ रही हैं (उदाहरण के लिए फ़ोटो ऐप के रूप में स्नैपी)।बहुत सारी छवियों (50-200) के साथ एक snappy UICollectionView कैसे प्राप्त करें?
मेरे पास UIImageView
के साथ एक कस्टम UICollectionViewCell
है जो इसके सबव्यूव के रूप में है। मैं UIImage.imageWithContentsOfFile:
के साथ, कोशिकाओं के अंदर UIImageViews में, फाइल सिस्टम से छवियों को लोड कर रहा हूं।
मैंने अभी कुछ दृष्टिकोणों की कोशिश की है लेकिन वे या तो छोटी हैं या प्रदर्शन के मुद्दे हैं।
नोट: मैं रूबीमोशन का उपयोग कर रहा हूं इसलिए मैं रूबी शैली में कोई भी कोड स्निपेट लिखूंगा।
सबसे पहले, यहाँ संदर्भ के लिए अपने कस्टम UICollectionViewCell वर्ग ...
class CustomCell < UICollectionViewCell
def initWithFrame(rect)
super
@image_view = UIImageView.alloc.initWithFrame(self.bounds).tap do |iv|
iv.contentMode = UIViewContentModeScaleAspectFill
iv.clipsToBounds = true
iv.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth
self.contentView.addSubview(iv)
end
self
end
def prepareForReuse
super
@image_view.image = nil
end
def image=(image)
@image_view.image = image
end
end
कार्य # 1
चीजों को सरल रखते हुए है ..
def collectionView(collection_view, cellForItemAtIndexPath: index_path)
cell = collection_view.dequeueReusableCellWithReuseIdentifier(CELL_IDENTIFIER, forIndexPath: index_path)
image_path = @image_paths[index_path.row]
cell.image = UIImage.imageWithContentsOfFile(image_path)
end
ऊपर स्क्रॉल/इसका उपयोग करके भयानक है। यह अजीब और धीमी है।
कार्य # 2
NSCache के माध्यम से कैशिंग का एक सा जोड़ें ...
def viewDidLoad
...
@images_cache = NSCache.alloc.init
...
end
def collectionView(collection_view, cellForItemAtIndexPath: index_path)
cell = collection_view.dequeueReusableCellWithReuseIdentifier(CELL_IDENTIFIER, forIndexPath: index_path)
image_path = @image_paths[index_path.row]
if cached_image = @images_cache.objectForKey(image_path)
cell.image = cached_image
else
image = UIImage.imageWithContentsOfFile(image_path)
@images_cache.setObject(image, forKey: image_path)
cell.image = image
end
end
फिर, चिड़चिड़ा और पहली पूर्ण स्क्रॉल पर धीमी गति से लेकिन फिर से यह चिकनी नौकायन है।
कार्य # 3
चित्र लोड करें एसिंक्रोनस रूप से ... (और कैशिंग रखने)
def viewDidLoad
...
@images_cache = NSCache.alloc.init
@image_loading_queue = NSOperationQueue.alloc.init
@image_loading_queue.maxConcurrentOperationCount = 3
...
end
def collectionView(collection_view, cellForItemAtIndexPath: index_path)
cell = collection_view.dequeueReusableCellWithReuseIdentifier(CELL_IDENTIFIER, forIndexPath: index_path)
image_path = @image_paths[index_path.row]
if cached_image = @images_cache.objectForKey(image_path)
cell.image = cached_image
else
@operation = NSBlockOperation.blockOperationWithBlock lambda {
@image = UIImage.imageWithContentsOfFile(image_path)
Dispatch::Queue.main.async do
return unless collectionView.indexPathsForVisibleItems.containsObject(index_path)
@images_cache.setObject(@image, forKey: image_path)
cell = collectionView.cellForItemAtIndexPath(index_path)
cell.image = @image
end
}
@image_loading_queue.addOperation(@operation)
end
end
इस होनहार देखा लेकिन वहाँ एक बग है कि मैं नीचे ट्रैक नहीं कर सकते है। प्रारंभिक दृश्य लोड पर सभी छवियां एक ही छवि होती हैं और जैसे ही आप पूरे ब्लॉक को दूसरी छवि के साथ लोड करते हैं लेकिन सभी में वह छवि होती है। मैंने इसे डिबग करने का प्रयास किया है लेकिन मैं इसे समझ नहीं सकता।
मैंने एनएसओपरेशन को Dispatch::Queue.concurrent.async { ... }
के साथ प्रतिस्थापित करने का भी प्रयास किया है, लेकिन ऐसा लगता है।
मुझे लगता है कि यह संभवतः सही दृष्टिकोण है यदि मैं इसे ठीक से काम करने के लिए प्राप्त कर सकता हूं।
कार्य # 4
हताशा में मैं UIImages के रूप में सिर्फ पूर्व लोड सभी छवियों को करने का निर्णय लिया ...
def viewDidLoad
...
@preloaded_images = @image_paths.map do |path|
UIImage.imageWithContentsOfFile(path)
end
...
end
def collectionView(collection_view, cellForItemAtIndexPath: index_path)
cell = collection_view.dequeueReusableCellWithReuseIdentifier(CELL_IDENTIFIER, forIndexPath: index_path)
cell.image = @preloaded_images[index_path.row]
end
यह थोड़ा धीमा और पहली में उछल साबित हुआ पूर्ण स्क्रॉल लेकिन उसके बाद सब अच्छा है।
सारांश
तो, अगर किसी को भी मुझे सही दिशा में बात कर सकते हैं मैं वास्तव में आभारी होगी। फ़ोटो ऐप यह कैसे करता है इतना अच्छा? किसी और के लिए
ध्यान दें: [स्वीकार किए जाते हैं] जवाब गलत कोशिकाओं में प्रदर्शित होने छवियों की मेरी समस्या का समाधान हो लेकिन मैं अभी भी आकार सही करने के लिए अपनी छवियों का आकार बदलने के बाद भी अस्थिर स्क्रॉल हो रही थी। मेरे कोड को नंगे जरूरी चीजों को अलग करने के बाद मुझे अंततः पता चला कि UIImage # imageWithContentsOfFile अपराधी था। भले ही मैं इस विधि का उपयोग करते हुए UIImages के कैश को पूर्व-गर्म कर रहा था, UIImage आंतरिक रूप से किसी प्रकार का आलसी कैशिंग करना प्रतीत होता है। यहां विस्तृत समाधान का उपयोग करने के लिए मेरे कैश वार्मिंग कोड को अपडेट करने के बाद - stackoverflow.com/a/10664707/71810 - अंततः मुझे सुपर चिकनी ~ 60FPS स्क्रॉलिंग थी।
हाँ, धन्यवाद! मुझे विश्वास नहीं है कि मैंने उसे नहीं देखा।प्रदर्शन अभी भी इस समय स्क्रॉल पर stuttering है लेकिन मेरे परीक्षण से मुझे विश्वास है कि सिर्फ इसलिए है कि मेरी छवियों कोशिकाओं के लिए बहुत बड़ी हैं। – alistairholt
किसी और के लिए नोट: इस उत्तर ने गलत कोशिकाओं में दिखाई देने वाली छवियों के मेरे मुद्दे को हल किया लेकिन आकारों को सही करने के लिए मेरी छवियों का आकार बदलने के बाद भी मुझे चंचल स्क्रॉलिंग मिल रही थी। मेरे कोड को नंगे जरूरी चीजों को अलग करने के बाद मुझे अंततः पता चला कि UIImage # imageWithContentsOfFile अपराधी था। भले ही मैं इस विधि का उपयोग करते हुए UIImages के कैश को पूर्व-गर्म कर रहा था, UIImage आंतरिक रूप से किसी प्रकार का आलसी कैशिंग करना प्रतीत होता है। यहां विस्तृत समाधान का उपयोग करने के लिए मेरे कैश वार्मिंग कोड को अपडेट करने के बाद - http://stackoverflow.com/a/10664707/71810 - अंततः मुझे सुपर चिकनी ~ 60FPS स्क्रॉलिंग थी। – alistairholt