5

मेरे पास एक UIViewController है जो सामान्य रूप से प्रस्तुत किया गया है। जब मैं स्मृति आवंटन उपकरण देखता हूं, दृश्य प्रस्तुत होने पर स्मृति उपयोग बढ़ता है, लेकिन जब यह निकल जाता है तो स्मृति जारी नहीं होती है। यदि मैं दृश्य को खोलना और बंद करना जारी रखता हूं, तो स्मृति केवल उच्च हो रही है। उपकरण स्मृति रिसाव की रिपोर्ट नहीं करता है! इसका कारण क्या हो सकता है? व्यू कंट्रोलर कोड नीचे है (मैंने didSelectRow कोड छोड़ दिया है)। डेलोक को हमेशा बुलाया जाता है।UIViewController में संभावित स्मृति रिसाव UITableView

संपादित करें - मैं एआरसी

उपयोग कर रहा हूँ ज

#import <UIKit/UIKit.h> 
@class OutlineTextUILabel; 

@interface StoreViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> { 

    int starCount; 
    NSMutableArray *_singleUseArray; 
    NSMutableArray *_fullUseArray; 

} 

@property (weak, nonatomic) IBOutlet UITableView *tableView; 
@property (weak, nonatomic) IBOutlet OutlineTextUILabel *starCountLbl; 
- (IBAction)exitBtnPressed:(id)sender; 

मीटर

#import "StoreViewController.h" 
#import "NSUserDefaults+MPSecureUserDefaults.h" 
#import "PowerUpCell.h" 
#import "OutlineTextUILabel.h" 
#import "PowerUpSingleton.h" 
#import "PowerUp.h" 

#define kPrefsNumberOfStars    @"numberOfStars" 

@interface StoreViewController() 

@end 

@implementation StoreViewController 
@synthesize tableView = _tableView; 
@synthesize starCountLbl; 

#pragma mark View Methods 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // Display star count 
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; 
    BOOL valid = NO; 
    starCount = [prefs secureIntegerForKey:kPrefsNumberOfStars valid:&valid]; 
    if (!valid) { 
     NSLog(@"Stars Tampered With!"); 
     self.starCountLbl.text = @"Err"; 
    } else { 
     self.starCountLbl.text = [NSString stringWithFormat:@"%d",starCount]; 
    } 

    // Tableview setup 
    CGRect frame2 = CGRectMake(0, 0, 320, 40); 
    UIView *footer = [[UIView alloc] initWithFrame:frame2]; 
    footer.backgroundColor = [UIColor clearColor]; 
    self.tableView.tableFooterView = footer; 
    self.tableView.opaque = NO; 
    self.tableView.backgroundView = nil; 
} 

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:YES]; 

    if (![[PowerUpSingleton sharedList] refreshArray]) { 
     NSLog(@"Error, %s",__FUNCTION__); 
    } else { 
     [self performSelectorOnMainThread:@selector(workOutSingleUseToDisplay) withObject:nil waitUntilDone:YES]; 
     [self performSelectorOnMainThread:@selector(workOutFullUseToDisplay) withObject:nil waitUntilDone:YES]; 
     [self.tableView reloadData]; 
    } 
} 

- (void)workOutSingleUseToDisplay 
{ 
    _singleUseArray = [[NSMutableArray alloc] init]; 
    for (PowerUp *pu in [[PowerUpSingleton sharedList] sharedArray]) { 
     if (!pu.fullUnlock) { 
      [_singleUseArray addObject:pu]; 
     } 
    } 
} 

- (void)workOutFullUseToDisplay 
{ 
    _fullUseArray = [[NSMutableArray alloc] init]; 
    for (PowerUp *pu in [[PowerUpSingleton sharedList] sharedArray]) { 
     if (pu.prefFullName != nil) { 
      [_fullUseArray addObject:pu]; 
     } 
    } 

} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown); 
} 

- (void)viewDidUnload { 
    [self setTableView:nil]; 
    [self setStarCountLbl:nil]; 
    [super viewDidUnload]; 
} 

#pragma mark TableView Setup Methods 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return 2; 
} 

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 
{ 
    if (section == 0) { 
     return @"Single Use"; 
    } else if (section == 1) { 
     return @"Use forever"; 
    } 

    return nil; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    if (section == 0) { 
     return [_singleUseArray count]; 
    } else if (section == 1) { 
     return [_fullUseArray count]; 
    } 

    return 0; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSString *cellIdentifier; 
    if (indexPath.section == 0) { 
     cellIdentifier = @"powerUpCellSingleUse"; 
    } else if (indexPath.section == 1) { 
     cellIdentifier = @"powerUpCell"; 
    } 

    PowerUpCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 
    if (cell == nil) { 
     cell = [[PowerUpCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 
    } 

    if (indexPath.section == 0) { 
     PowerUp *tmpPU = [_singleUseArray objectAtIndex:indexPath.row]; 
     cell.descriptionLbl.text = tmpPU.displayName; 
     int cost = tmpPU.costSingle; 
     cell.costLbl.text = [NSString stringWithFormat:@"%d",cost]; 
     if (cost > starCount) { 
      cell.costLbl.textColor = [UIColor redColor]; 
     } else { 
      cell.costLbl.textColor = [UIColor blueColor]; 
     } 
     int howMany = tmpPU.numberOwned; 
     cell.howManyLbl.text = [NSString stringWithFormat:@"%d",howMany]; 

    } else if (indexPath.section == 1) { 
     PowerUp *tmpPU = [_fullUseArray objectAtIndex:indexPath.row]; 
     cell.descriptionLbl.text = tmpPU.displayName; 
     int cost = tmpPU.costFull; 
     cell.costLbl.text = [NSString stringWithFormat:@"%d",cost]; 
     if (cost > starCount) { 
      cell.costLbl.textColor = [UIColor redColor]; 
     } else { 
      cell.costLbl.textColor = [UIColor blueColor]; 
     } 
     if (tmpPU.fullUnlock) { 
      cell.costLbl.textColor = [UIColor greenColor]; 
      cell.costLbl.text = @"---"; 
     } 
    } 

    return cell; 
} 

#pragma mark - 

- (IBAction)exitBtnPressed:(id)sender 
{ 
    [self dismissModalViewControllerAnimated:YES]; 
} 

- (void)dealloc 
{ 
    NSLog(@"%s",__FUNCTION__); 
    self.tableView = nil; 
    self.starCountLbl = nil; 
} 

@end 

संपादित करें ------------- कुछ नहीं लगता है ठीक होने के लिए। मैंने सेल एलोक में एक एनएसएलॉग जोड़ा है, और इसे कभी भी नहीं कहा जाता है, भले ही कोशिकाएं बनती हैं!

PowerUpCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 
    if (cell == nil) { 
     NSLog(@"new cell"); 
     cell = [[PowerUpCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 
    } 

संपादित 1st जुलाई ------ मैं एक नेविगेशन नियंत्रक जोड़ दिया है और अब मोडल के बजाय धक्का का उपयोग करें और इस समस्या को अभी भी यहाँ है। मैंने कुछ बार विचारों के बीच पीछे और आगे बढ़कर इंस्ट्रूमेंट्स के साथ ढेर शॉट्स ले लिए हैं और ऐसा लगता है कि कोशिकाएं अभी भी आसपास लटक रही हैं, क्योंकि यह स्क्रीनशॉट अभी भी दृश्य के पिछले लोड से इशारा पहचानकर्ता दिखाता है। screen shot

+0

viewWillAppear के अंदर आप performOnMainThread का उपयोग करते हैं। इसकी आवश्यकता नहीं है, मुख्य थ्रेड पर ViewWillAppear होता है। –

+0

मैंने केवल इस विधि का उपयोग किया है, इसलिए मैं प्रतीक्षा कर सकता हूं कोई भी नहीं: हाँ तो अब मैं तालिका खींचने से पहले सरणी भर चुका हूं। – Darren

+0

बस इसे आज़माएं: [स्वयं का कामOutFullUseToDisplay]। आपको एहसास है कि उद्देश्य-सी अनुक्रमिक सही है? –

उत्तर

3

यह इसलिए क्योंकि आप के बजाय strong का उपयोग कर के, weak के रूप में अपने IBOutlets का इस्तेमाल किया।

मुझे वास्तव में विश्वास है कि यह एक्सकोड पर्यावरण में एक दोष है, क्योंकि इसे आपको इस तरह के व्यवहार की चेतावनी दी जानी चाहिए।

एक सर्वोत्तम अभ्यास के रूप में, मैं सुझाव देता हूं कि एक्सकोड इंटरफ़ेस बिल्डर में कोड को दृश्यों को खींचकर आईबीओटलेट उत्पन्न करने का सुझाव देगा, इस तरह के कष्टप्रद नुकसान से बचने के लिए।

+0

हां, मैंने यह सब ऊपर कहा था। एक स्पष्टीकरण क्यों अच्छा होगा। मैंने कुछ समय पहले आईबीओटलेट्स के लिए कमजोर लिंक का उपयोग करने के लिए पढ़ा था। मैं एक्सकोड को आईबीओटलेट उत्पन्न करने देता हूं लेकिन पॉपअप में आपके पास विकल्प है मजबूत या कमजोर। इसके अलावा, मैंने सोचा कि मजबूत होने के मुकाबले कुछ पीछे छोड़ने का अधिक मौका होगा! मैंने सोचा था कि दृश्य हटा दिए जाने पर एक कमजोर संदर्भित वस्तु हटा दी जाएगी। – Darren

+1

यह वास्तव में निर्भर करता है। आपको आईबीओटलेट्स के लिए मजबूत लिंक का उपयोग करना चाहिए जो कि फाइलऑनर के स्वामित्व में हैं, और सबव्यू द्वारा उपयोग किए जाने वाले आईबीओटलेट्स के कमजोर लिंक हैं। https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs।एचटीएमएल # // apple_ref/doc/uid/10000051i-CH4-SW6 कृपया आईओएस (और ओएस एक्स नहीं) – Gilbert

+2

से संबंधित भागों का ध्यान रखें, मेरा मानना ​​है कि आपके विशिष्ट मामले में, UITableView कक्षों को मजबूत के साथ आवंटित किया गया था लिंक, और तालिकादृश्य (पर्यवेक्षण) का संदर्भ दिया। दूसरी तरफ, यूआईटीबलव्यू (जो कमजोर है), कोशिकाओं का भी संदर्भ दे रहा था - जिसने उनमें से किसी को भी – Gilbert

0

[संपादित करें]

अपने viewWillAppear विधि में, प्रिंट किए गए हैं, यह देखने के लिए कितनी बार आप अपने बाकी खंड के माध्यम से चलते हैं। मेरे लिए ऐसा लगता है कि आप अपना काम कॉल करते हैं OutSingleUseToDisplay और workOutFullUseToDisplay विधियों। प्रत्येक बार जब आप उन्हें कॉल करते हैं, तो आप _singleUseArray आवंटित कर रहे हैं और _fullUseArray। सिर्फ इसलिए कि आप किसी दृश्य में बाहर और बाहर जाते हैं, इसका मतलब यह नहीं है कि यह डेलोक को कॉल करता है, या यह आपके वर्तमान सरणी को स्वत: रिलीज़ करेगा। मुझे लगता है कि आप जो देख रहे हैं वह यह है कि जब आप अपने विचार से बाहर निकलते हैं, तो यह उन दो सरणी को जारी नहीं करता है, लेकिन उन्हें पुन: आवंटित करने का प्रयास करता है।

[मूल] ठीक है, आपके विचार में डिडलोड, आप एक आवंटन करते हैं। आपके डीलोक में, मुझे एक [पाद लेख रिलीज] दिखाई नहीं देता है। यह तुम्हारा रिसाव हो सकता है !!! और न ही मैं अपने _singleUseArray या _fullUseArray सरणियों के रिहा

+0

मैं एआरसी का उपयोग कर रहा हूं इसलिए मैन्युअल रूप से रिलीज़ नहीं किया जा सकता है। मैंने _singleUseArray = nil जोड़ने की कोशिश की है; _fullUseArray = nil; पाद लेख = शून्य; dealloc करने के लिए लेकिन कोई बदलाव नहीं। – Darren

+1

आपको अपनी शुरुआती पोस्ट में एआरसी के बारे में बताना चाहिए था, क्योंकि मुझे लगता है कि यह उत्तर के लिए दृढ़ संकल्प कर रहा है। – Martin

+0

इसके बारे में क्षमा करें। मैं इसे प्रश्न में जोड़ दूंगा। मैंने 2 सरणी आवंटन को viewDidLoad में स्थानांतरित कर दिया है, इसलिए उन्हें निश्चित रूप से केवल एक बार बुलाया जाएगा, लेकिन स्मृति पैटर्न अभी भी वही हैं। दृश्य नियंत्रक dealloc हर बंद पर बुलाया जा रहा है। कोई अन्य विचार? – Darren

0

मुझे यकीन है कि अगर मैं anwer मिला नहीं कर रहा हूँ क्यों दिखाई देता है, लेकिन वहाँ अपने कोड में कुछ अजीब है:

अपने कमजोर गुण का उपयोग कर रहे हैं:

@property (weak, nonatomic) IBOutlet UITableView *tableView; 
@property (weak, nonatomic) IBOutlet OutlineTextUILabel *starCountLbl; 

लेकिन the doc (खोज "कमजोर") के अनुसार, weak प्रोपोर्टी assign के समान है।

आप में dealloc, आप

self.tableView = nil; 
self.starCountLbl = nil; 

मैं बहुत यकीन है कि इन गुणों का उत्पन्न सेटर उन्हें बिल्कुल भी जारी नहीं करता हूँ है!

लेकिन अगर आप की तरह अपने गुण की घोषणा:

@property (nonatomic, retain) IBOutlet UITableView *tableView; 
@property (nonatomic, retain) IBOutlet OutlineTextUILabel *starCountLbl; 

उत्पन्न सेटर की तरह

(void)setTableView(UITableView *)newTableView { 
    [tableView release]; 
    if(newTableView != nil) 
     tableView = [newTableView retain]; 
} 

होगा और अपने गुण जारी किया जाएगा।

+0

मैंने वास्तव में केवल self.tableView = nil और self.starCountLbl = nil को रिलीज करने की कोशिश करते समय dealloc को जोड़ा। वास्तव में इसकी आवश्यकता नहीं है क्योंकि वे वैसे भी कमजोर संदर्भ हैं और दृश्य नियंत्रक जारी होने पर रिलीज़ होते हैं। – Darren

0

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

PowerUpCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 
if (cell == nil) { 
    NSLog(@"new cell"); 
    cell = [[PowerUpCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 
} 

तुम देखो, cellnil होने के लिए नहीं जा रहा है ... यह API दस्तावेज़ में dequeueReusableCellWithIdentifier: के लिए कहा गया है::

वापसी मूल्य



यह आपके कोड है पुन: प्रयोज्य-सेल कतार में ऐसी कोई वस्तु मौजूद नहीं है, तो संबंधित पहचानकर्ता या शून्य के साथ एक UITableViewCell ऑब्जेक्ट।

_singleUseArray = [[NSMutableArray alloc] init]; 

और

_fullUseArray = [[NSMutableArray alloc] init]; 

, जब आप

NSMutableArray *_singleUseArray; 
NSMutableArray *_fullUseArray; 

मुझे लगता है कि घोषित द्वारा:

वैसे भी, अगर वहाँ लीक कर रहे हैं, हो सकता है वे बहुत ज्यादा के कारण होता है डिफ़ॉल्ट दोनों को __strong क्वालीफ के साथ असाइन किया गया था ier। मुझे सच में यकीन नहीं है लेकिन यह समस्या का असली कारण हो सकता है। इसके बजाय इसे घोषित करने के बारे में कैसे?

NSMutableArray * __weak _singleUseArray; 
NSMutableArray * __weak _fullUseArray; 

इसके अलावा,

_singleUseArray = [[NSMutableArray alloc] init]; 

और

_fullUseArray = [[NSMutableArray alloc] init]; 

घोषित करने से पहले कैसे nil करने के लिए पहले यह बताए पिछले संदर्भ को दूर करने के बारे में क्या?

_singleUseArray = nil; 
_singleUseArray = [[NSMutableArray alloc] init]; 

और

_fulUseArray = nil; 
_fullUseArray = [[NSMutableArray alloc] init]; 
+0

मैंने रिसाव उपकरण का उपयोग किया और यह यहां एक रिसाव नहीं दिखाया, भले ही स्मृति को हर बार लोड करने के लिए बढ़ाया जाता है। – Darren

+0

सरणी को बाहर निकालने में पूरी तरह से समस्या है :-( – Darren

+0

मुझे 1 मेमोरी लीक दिखाई देता है, लेकिन मुझे नहीं लगता कि यह संबंधित है। यह जिम्मेदार फ्रेम = [NSURL (NSURL) पथ] कहता है और जब मैं इसे क्लिक करता हूं ऐसा लगता है कि स्टोरीबोर्ड लोडिंग के साथ इसका कुछ संबंध है। – Darren

2

ऐसा लगता है कि आप पहले से ही इस के आसपास के कुछ तरीके पाया है, लेकिन सिर्फ मामले में यह मदद करता है:

1) सुनिश्चित करें कि आप नहीं मिला है Zombies चालू करते समय आप डिबगिंग रहे हैं के रूप में इस के लिए वस्तुओं का कारण बनता है बनाओ, आपको लगता है कि वे dealloc-ed होना चाहिए (योजना संपादित करें -> रन -> डायग्नोस्टिक्स) के बाद चारों ओर लटका।

2) आप एआरसी का उपयोग कर रहे हैं और इसलिए मैं स्टोरीबोर्ड या कम से कम प्रोटोटाइप UITableView कक्षों को अपने स्टोरीबोर्ड/एनआईबी में मानता हूं? यदि ऐसा है, तो कारण आपके NSLog() को नीचे कभी नहीं कहा जाता है क्योंकि dequeueReusableCellWithIdentifier कॉल परिभाषित सेलइंडिफायर के माध्यम से इन प्रोटोटाइप कोशिकाओं से कोशिकाओं को बनाने के लिए जानता है। बहुत आसान

PowerUpCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 
    if (cell == nil) { 
     NSLog(@"new cell"); 
     cell = [[PowerUpCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 
    } 

आप UITableView पर भरोसा करते हैं UITableViewCells के इस कैश का प्रबंधन करने के लिए, और उन्हें उचित रूप से जारी करने के लिए है। तो यह संभव है कि वे सिर्फ चारों ओर लटक रहे हैं क्योंकि आपका UITableView जारी नहीं किया जा रहा है (हालांकि मुझे लगता है कि आप यह कह रहे हैं)।

+0

को हटाने की इजाजत नहीं दी, इससे मेरी मदद मिली! @ChrisH इसे पोस्ट करने के लिए धन्यवाद। वास्तव में आपकी पहली युक्ति ने मुझे कुछ अतुलनीय व्यवहार को ट्रैक करने में मदद की। इस तरह के पोस्ट स्टैक ओवरफ़्लो को और भी बेहतर बनाते हैं! – scrrr

+0

क्या आप साझा कर सकते हैं कि आप क्या समस्या थी? मुझे लगता है कि मेरे ऐप में कुछ ऐसा हो सकता है। – Piotr