2013-05-25 7 views
7

मैंने अभी एक UICollectionView बनाया है जिसमें उपयोगकर्ता अपने फोन से छवियों को ऐप में फोटो एलबम सुविधा में जोड़ सकते हैं। मेरे पास दस्तावेज़ निर्देशिका में उपनिर्देशिका में छवियां सहेजी गई हैं ताकि अधिक जोड़ा जा सके और हटाया जा सके। हालांकि, जब मैं संग्रह दृश्य को ऊपर और नीचे स्क्रॉल करता हूं, तो यह बहुत कमजोर होता है।UICollectionView scrolling धीमा है

मैं स्क्रॉल को अच्छा और चिकनी कैसे बना सकता हूं?

मेरे कोड: पहले 16 चित्र हैं कि उसके बाद दस्तावेजों निर्देशिका में एक उपनिर्देशिका से कर रहे हैं पूर्व निर्धारित छवियों सब कुछ

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    CollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Custom" forIndexPath:indexPath]; 
    //Current index number 
    int index=indexPath.section * noOfSection + indexPath.row; 
    //Check if its the preset photos 
    if(index<16){ 
     NSString *name=[recipePhotos objectAtIndex:indexPath.section * noOfSection + indexPath.row]; 
     cell.imageView.image=[UIImage imageNamed:name]; 
    } 

//not preset photos, so retrieve the photos the user added 
    else { 
     NSData *data= [NSData dataWithContentsOfFile:[recipePhotos objectAtIndex:index]]; 
     UIImage *theImage=[UIImage imageWithData:data]; 

     cell.imageView.image=theImage; 
     data=nil; 
    } 

    return cell; 
} 

समय प्रोफाइलर मुझे दिया इस

Running Time Self  Symbol Name 
568.0ms 63.1% 0.0  Main Thread 0x4048 
320.0ms 35.5% 0.0  _pthread_start 0x405e 
320.0ms 35.5% 0.0  thread_start 
320.0ms 35.5% 0.0  _pthread_start 
320.0ms 35.5% 0.0  0x1084be960 
310.0ms 34.4% 1.0   0x1084be6f0 
7.0ms 0.7% 0.0   mach_msg 
2.0ms 0.2% 2.0   objc_msgSend 
1.0ms 0.1% 1.0   -[NSAutoreleasePool release] 
4.0ms 0.4% 0.0  _dispatch_mgr_thread 0x4052 
4.0ms 0.4% 0.0  _dispatch_mgr_thread 
4.0ms 0.4% 0.0  _dispatch_mgr_invoke 
4.0ms 0.4% 4.0  kevent 
3.0ms 0.3% 0.0  _dispatch_worker_thread2 0x62b24 
3.0ms 0.3% 1.0  start_wqthread 
3.0ms 0.3% 0.0  _dispatch_worker_thread2 0x62a84 
3.0ms 0.3% 0.0  start_wqthread 
3.0ms 0.3% 0.0  _pthread_wqthread 
3.0ms 0.3% 0.0  _dispatch_worker_thread2 
3.0ms 0.3% 0.0   _dispatch_queue_invoke 
3.0ms 0.3% 0.0   _dispatch_queue_drain 
3.0ms 0.3% 0.0   _dispatch_client_callout 
2.0ms 0.2% 0.0   my_io_execute_passive_block 
1.0ms 0.1% 0.0    __86-[NSPersistentUIManager writePublicPlistWithOpenWindowIDs:optionallyWaitingUntilDone:]_block_invoke_0835 
1.0ms 0.1% 0.0    -[NSPersistentUIManager writePublicPlistData:] 
1.0ms 0.1% 0.0    -[NSURL(NSURLPathUtilities) URLByAppendingPathComponent:] 
1.0ms 0.1% 0.0    -[NSURL getResourceValue:forKey:error:] 
1.0ms 0.1% 0.0     CFURLCopyResourcePropertyForKey 
1.0ms 0.1% 0.0    __block_global_2 
1.0ms 0.1% 0.0    -[NSPersistentUIManager writeRecords:withWindowInfos:flushingStaleData:] 
1.0ms 0.1% 0.0   _dispatch_call_block_and_release 
1.0ms 0.1% 0.0    0x1084b8580 
1.0ms 0.1% 0.0    mach_msg_send 
1.0ms 0.1% 0.0    mach_msg 
1.0ms 0.1% 1.0    mach_msg_trap 
1.0ms 0.1% 0.0  _pthread_struct_init 0x62a83 
1.0ms 0.1% 0.0  start_wqthread 
1.0ms 0.1% 0.0  _pthread_wqthread 
1.0ms 0.1% 1.0  _pthread_struct_init 
1.0ms 0.1% 0.0  start_wqthread 0x62a7f 
+1

कितने छवियों को ध्यान में रखते हैं? मेरे अनुभव से, बहुत सारी छवियां फ्रेम दर को धीमा कर सकती हैं। – LAMBORGHINI

+1

यह केवल निर्देशिका से छवियों को लोड करने वाले कक्षों के साथ होता है .. ऊपर अपना कोड देखें .. मैंने अभी इसे अपडेट किया है @ कोडबैंडिट्स –

+0

क्या आप 'संग्रहसेल' में कोई कस्टम ड्राइंग करते हैं? – rog

उत्तर

2

तो कुछ गड़बड़ करने के बाद, मुझे पता चला है कि समस्या कुछ कारकों पर आधारित थी।

वन- थंबनेल के लिए छवियां बहुत बड़ी थीं, इसलिए मैंने जो किया वह छवियों की एक अलग सरणी थी जिसमें छोटे छवि आकार होते थे जो सेल फिट बैठते थे। दो- @ggrana की मदद से, एक अलग थ्रेड खोलने से प्रक्रिया बढ़ गई और इसे कम लगी हुई। तीन- मैंने यह भी पाया कि छवि स्थानों की बजाय छवियों की एक सरणी तेज थी - केवल समस्या यह है कि यह और अधिक स्मृति लेता है।

+0

यदि आपके पास कई छवियां नहीं हैं, तो मेरा मतलब है औसत उपयोगकर्ता आपके संग्रह दृश्य के माध्यम से स्क्रॉल करता है, वे अंत में एक ही स्मृति का उपयोग कर समाप्त हो जाएंगे। तो अगर छवियों की सरणी तेज है, तो उस तरह जाओ। –

+0

आपको इस http://stackoverflow.com/a/26034382/294884 की आवश्यकता है और यह http://stackoverflow.com/a/25604378/294884 – Fattie

3

आप करने की आवश्यकता होगी टेबलव्यू में आपको जिस तरह की आवश्यकता है, उसके दृष्टिकोण, आपको दृश्यों का पुन: उपयोग करने की आवश्यकता होगी, जैसे कि आप तालिका दृश्य में अपनी कोशिकाओं का पुन: उपयोग करते हैं।

एक वास्तव में अच्छा ट्यूटोरियल रे Wenderlich से एक है: पहला भाग आप बुनियादी है में

, दूसरा एक वे पुन: प्रयोज्य विचारों के बारे में बात में, आप लिंक पर एक नज़र डालें:

http://www.raywenderlich.com/22417/beginning-uicollectionview-in-ios-6-part-22

संपादित

छवियों async लोड करने के लिए उदाहरण:

अपने सेल एक विधि उदाहरण के लिए loadImageFromFile, उस पथ आप इसे इस तरह से कैलोरी जाएगा प्राप्त करता है पर बनाएँ:

:

[cell loadImageFromFile:[recipePhotos objectAtIndex:index]]; 

तो और तरह दिखेगा (हो सकता है आप कुछ अनुकूलित करने की आवश्यकता ...)

- (void) loadImageFromFile:(NSString*)path{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{ 
     NSData *data= [NSData dataWithContentsOfFile:path]; 
     UIImage *theImage=[UIImage imageWithData:data]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      cell.imageView.image=theImage; 
    }); 
}); 
+0

मैं पुन: प्रयोज्य कोशिकाओं का उपयोग कर रहा हूं ... @Grrana –

+0

से ऊपर मेरा कोड है, आपको पृष्ठभूमि में छवि को लोड करने की आवश्यकता होगी, और लोड होने पर आपको सेल में छवि को अपडेट करने की आवश्यकता होगी, अन्यथा आपकी स्क्रॉल छवि जारी रखने के लिए प्रतीक्षा करेगी धीमी गति से। – ggrana

+0

ठीक है, पृष्ठभूमि में इसकी देखभाल करने के लिए सबसे अच्छा तरीका क्या है। क्या मुझे मुख्य धागे से अलग होना होगा? यदि हां, तो कैसे @ggrana –

3

@ggrana का सही विचार है। एसिंक लोड हो रहा है निश्चित रूप से मदद करेगा। हालांकि, अगर आप हर बार फाइल से लोड करते हैं तो भी आप अनावश्यक काम कर रहे हैं। विचार करने की एक बात NSCache के साथ एसिंक लोडिंग को बढ़ाएगी। यह मूल रूप से NSDictionary है लेकिन स्मृति प्रबंधन होता है और स्मृति दबाव होने पर डेटा को डंप करता है।

तो यदि आपके पास मेमोरी बजट है, तो आप वास्तव में फ्लाई पर अपने थंबनेल बना सकते हैं (इसलिए आपको आकार को हार्ड कोड नहीं करना पड़ता है) और उन्हें कैश में स्टोर करें। इस तरह आपकी छवियां केवल पहली बार पॉप होती हैं। उसके बाद हर बार, वे तुरंत लोड हो जाते हैं।

तुम इतनी की तरह उपयोग कर सकते हैं:

@implementation ... 
{ 
    NSCache * _johnny; // get it? 
} 

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    [cell setImage:nil]; // since they are reused, prevents showing an old image 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     UIImage * sticker = [self thumbnailOfSize:CGSizeMake(desiredImageWidth, desiredImageHeight) 
              forIndex:[indexPath row]]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [cell setImage:sticker]; 
     }); 
    }); 
} 

// load image from disk and cache thumbnail version 
- (UIImage*) thumbnailOfSize:(CGSize)size forIndex:(NSInteger)index 
{ 
    NSString * cacheKey = [NSString stringWithFormat:@"%@ %d", NSStringFromCGSize(size), index]; 
    UIImage * image = [_johnny objectForKey:cacheKey]; 

    if (!image) { 
     image = [UIImage imageWithContentsOfFile:_imagePaths[index]]; 

     float desiredWidth = size.width; 
     float desiredHeight = size.height; 
     float actualHeight = image.size.height; 
     float actualWidth = image.size.width; 
     float imgRatio = actualWidth/actualHeight; 
     float maxRatio = desiredWidth/desiredHeight; 

     if(imgRatio != maxRatio) { 
      if(imgRatio < maxRatio) { 
       imgRatio = desiredHeight/actualHeight; 
       actualWidth = imgRatio * actualWidth; 
       actualHeight = desiredHeight; 
      } else { 
       imgRatio = desiredWidth/actualWidth; 
       actualHeight = imgRatio * actualHeight; 
       actualWidth = desiredWidth; 
      } 
     } 

     CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight); 
     UIGraphicsBeginImageContextWithOptions(rect.size, FALSE, 0); // do right thing for retina 
     [image drawInRect:rect]; 
     image = UIGraphicsGetImageFromCurrentImageContext(); 
     UIGraphicsEndImageContext(); 

     // here's johnny 
     [_johnny setObject:image forKey:cacheKey]; 
    } 

    return image; 
} 
+0

यह दृष्टिकोण अच्छी तरह से काम करता है। कुछ बिंदु: 1) आप 'सेलफोर इटिम ...' 2 में सेल सृजन/डेक्यू लाइन खो रहे हैं) यदि कोई उपयोगकर्ता लंबे संग्रह के निचले हिस्से तक स्क्रॉल करता है तो बहुत तेज़ी से, नीचे की कोशिकाएं चक्र के माध्यम से दिखाई दे सकती हैं एसिंक कॉल के समूह के रूप में छवियों की एक श्रृंखला उस पुन: उपयोग किए गए सेल के अंत में छवि को अद्यतन करती है। 'IndexPathsForVisibleCells 'की आखिरी मिनट की जांच यह हल करती है (मूल रूप से" क्या यह सूचकांक पथ अभी भी दिखाई देता है? यदि नहीं, तो छवि को अपडेट न करें)। –