Note that there are some explanatory texts on larger screens.

plurals
  1. PORetain Cycle on Retain Cycles
    text
    copied!<p>I'm seeing a gradual build up of memory that I think might be a retain cycle. </p> <p><strong>When does this happen:</strong> Click on a custom cell that expands and injects a nib with 3 buttons into the expanded area. Clicking the cell again closes the cell, shrinks the cell's tablerow height, rotates an open indicator and removes the previously injected nib.</p> <p>If I open and close the cell multiple times I see the memory gradually building up. </p> <p>Any ideas what might be causing this would be greatly appreciated. </p> <p>Sorry I don't have enough reputation to post photos. </p> <p>Build up: <img src="https://i.stack.imgur.com/P064S.png" alt="http://imgur.com/Up6iAPr"></p> <p>Example of retained objects(mostly Animation related): <img src="https://i.stack.imgur.com/JTEK0.png" alt="http://imgur.com/8X2Tr8L"></p> <p>EDIT: Using ARC and on iOS 6</p> <h2>MasterViewController - TableView Functions</h2> <pre><code>#pragma mark - UITABLEVIEW - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.topicsArray count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *CellIdentifier2 = @"SRCollapsibleCellClosed"; SRCollapsibleCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2]; if (cell == nil) { cell = [[SRCollapsibleCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2]; } SRTopic *topic = [self.topicsArray objectAtIndex:indexPath.row]; [cell updateWithTopic:topic]; if([self isCellOpen:indexPath]){ CGAffineTransform transformation = CGAffineTransformMakeRotation(M_PI/2); cell.arrow.transform = transformation; if(![self hasChoiceBox:cell]){ [self insertChoiceBox:cell atIndex:indexPath]; } } else{ CGAffineTransform transformation = CGAffineTransformMakeRotation(0); cell.arrow.transform = transformation; } return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if([self isCellOpen:indexPath]){ [self closeCellAtIndexPath:indexPath]; } else{ NSIndexPath * openCell= self.openCellIndex; NSIndexPath * newOpenCell= indexPath; [self closeCellAtIndexPath:openCell]; [self openCellAtIndexPath:newOpenCell]; } [tableView beginUpdates]; [tableView endUpdates]; [tableView deselectRowAtIndexPath:indexPath animated:NO]; } -(CGFloat)tableView: (UITableView*)tableView heightForRowAtIndexPath: (NSIndexPath*) indexPath { if([indexPath isEqual:self.openCellIndex]){ return 217.0; } else { return 63.0; } } -(void)rotateCellArrowAtIndexPath:(NSIndexPath*)indexPath willOpen:(bool)willOpen Animated:(bool)animated{ // Change Arrow orientation SRCollapsibleCell *cell = (SRCollapsibleCell*) [self.topicsTableView cellForRowAtIndexPath:indexPath]; CGAffineTransform transformation; if(willOpen){ transformation = CGAffineTransformMakeRotation(M_PI/2); } else { transformation = CGAffineTransformMakeRotation(0); } if(animated){ [UIView animateWithDuration:.2 delay:0 options:nil animations:^{ cell.arrow.transform = transformation; } completion:nil]; } else{ cell.arrow.transform = transformation; } } -(BOOL)isCellOpen:(NSIndexPath *)indexPath{ return [indexPath isEqual:self.openCellIndex]; } -(void)closeCellAtIndexPath:(NSIndexPath*)indexPath{ //NSLog(@"Cell closing"); [self rotateCellArrowAtIndexPath:indexPath willOpen:NO Animated:YES]; [self removeSRChoiceBoxFromCellAtIndexPath:indexPath]; self.openCellIndex = nil; } -(void)openCellAtIndexPath:(NSIndexPath*)indexPath{ [self rotateCellArrowAtIndexPath:indexPath willOpen:YES Animated:YES]; SRCollapsibleCell *cell = (SRCollapsibleCell*)[self.topicsTableView cellForRowAtIndexPath:indexPath]; [self insertChoiceBox:cell atIndex:indexPath]; self.openCellIndex = indexPath; } -(void)removeSRChoiceBoxFromCellAtIndexPath:(NSIndexPath *)indexPath{ SRCollapsibleCell *cell = (SRCollapsibleCell*) [self.topicsTableView cellForRowAtIndexPath:indexPath]; for(id subview in cell.SRCollapsibleCellContent.subviews){ if([subview isKindOfClass:[SRChoiceBox class]]){ SRChoiceBox *tempBox = subview; [tempBox removeFromSuperview]; tempBox.delegate = nil; tempBox = nil; } } } -(void)insertChoiceBox: (SRCollapsibleCell *)cell atIndex:(NSIndexPath *) indexPath { //SRChoiceBox *newBox = [[SRChoiceBox alloc] initWithFrame:CGRectMake(0, 0, 310, 141)]; SRChoiceBox *newBox = [[SRChoiceBox alloc] init]; SRTopic *topic = [self.topicsArray objectAtIndex:indexPath.row]; [newBox updateWithSRTopic:topic]; newBox.delegate = self; [cell.SRCollapsibleCellContent addSubview:newBox]; cell = nil; topic = nil; newBox = nil; } -(bool)hasChoiceBox:(SRCollapsibleCell *)cell{ for(UIView *subview in cell.SRCollapsibleCellContent.subviews){ if([subview isKindOfClass:[SRChoiceBox class]]){ return true; } } return false; } </code></pre> <h2>SRChoiceBox - UIView object that gets inserted into cell</h2> <pre><code>//.h @protocol SRChoiceBoxDelegate &lt;NSObject&gt; -(void)positionWasChoosen: (NSString *)choice topicId: (NSNumber *)topicId; @end @interface SRChoiceBox : UIView -(id) initWithLabel: (NSDictionary *)labels andTopicID: (NSNumber *)topicId andFrame:(CGRect)frame; @property (nonatomic, weak) IBOutlet UIView *SRChoiceBox; @property (nonatomic, strong) NSNumber *SRTopicId; @property (nonatomic, weak) id&lt;SRChoiceBoxDelegate&gt; delegate; @property (weak, nonatomic) IBOutlet UILabel *agreeCount; @property (weak, nonatomic) IBOutlet UILabel *disagreeCount; @property (weak, nonatomic) IBOutlet UILabel *observeCount; -(IBAction)buttonPress:(id)sender; -(void)updateWithSRTopic:(SRTopic *)topic; .... //.m -(id)init{ self = [super init]; if (self) { UINib *nib = [UINib nibWithNibName:@"SRChoiceBox" bundle:nil]; NSArray *q = [nib instantiateWithOwner:self options:nil]; [self addSubview:q[0]]; } return self; } -(void)updateWithSRTopic:(SRTopic *)topic { self.SRTopicId = topic.topicId; self.agreeCount.text = [NSString stringWithFormat: @"%@",topic.agreeDebaters]; self.disagreeCount.text = [NSString stringWithFormat: @"%@",topic.disagreeDebaters]; self.observeCount.text = [NSString stringWithFormat: @"%@",topic.observers]; } - (IBAction)buttonPress:(id) sender { int tag = [sender tag]; switch (tag) { case 0: [self.delegate positionWasChoosen:@"agree" topicId:self.SRTopicId]; break; case 1: [self.delegate positionWasChoosen: @"disagree" topicId:self.SRTopicId]; break; case 2: [self.delegate positionWasChoosen: @"observe" topicId:self.SRTopicId]; break; default: break; } } - (void)dealloc { self.SRChoiceBox =nil; self.SRTopicId=nil; self.delegate=nil; self.agreeCount=nil; self.disagreeCount=nil; self.observeCount=nil; //NSLog(@"choicebox deallocated: %@", self); } </code></pre> <h2>SRCollapsibleCell -- Reusable cell</h2> <p>//.h</p> <pre><code>@interface SRCollapsibleCell : UITableViewCell @property (strong) NSNumber *topicId; @property (strong) NSDictionary *topicStats; @property (weak, nonatomic) IBOutlet UILabel *title; @property (weak, nonatomic) IBOutlet UILabel *subtitle; @property (weak, nonatomic) IBOutlet UILabel *agreeDebaters; @property (weak, nonatomic) IBOutlet UILabel *disagreeDebaters; @property (weak, nonatomic) IBOutlet UILabel *observers; @property (weak, nonatomic) IBOutlet UIImageView *arrow; @property (weak, nonatomic) IBOutlet UIView *SRCollapsibleCellContent; //-(void)updateWithTopic:(NSDictionary *) stats; -(void)formatTitle:(NSString *)title; -(void)updateWithTopic: (SRTopic *)topic; @end </code></pre> <p>//.m</p> <pre><code>@implementation SRCollapsibleCell - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { } return self; } -(void)formatTitle:(NSString *)title{ if(title.length&lt;30){ self.title.text= title; self.subtitle.text =@""; } else { NSArray *splitString = [self splitString:title maxCharacters:30]; self.title.text = splitString[0]; self.subtitle.text = splitString[1]; splitString = nil; title = nil; } } ////http://www.musicalgeometry.com/?p=1197 - (NSArray *)splitString:(NSString*)str maxCharacters:(NSInteger)maxLength { NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:1]; NSArray *wordArray = [str componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSInteger numberOfWords = [wordArray count]; NSInteger index = 0; NSInteger lengthOfNextWord = 0; while (index &lt; numberOfWords &amp;&amp; tempArray.count&lt;2) { NSMutableString *line = [NSMutableString stringWithCapacity:1]; while ((([line length] + lengthOfNextWord + 1) &lt;= maxLength) &amp;&amp; (index &lt; numberOfWords)) { lengthOfNextWord = [[wordArray objectAtIndex:index] length]; [line appendString:[wordArray objectAtIndex:index]]; index++; if (index &lt; numberOfWords) { [line appendString:@" "]; } } [tempArray addObject:line]; NSMutableString *subtitle = [NSMutableString stringWithCapacity:1]; while(index&lt;numberOfWords){ [subtitle appendString:[wordArray objectAtIndex:index]]; [subtitle appendString:@" "]; index++; } [tempArray addObject:subtitle]; break; } return tempArray; } //Breaks MVC but it makes the MasterVC cleaner -(void)updateWithTopic: (SRTopic *)topic { [self formatTitle:topic.title]; self.topicId = topic.topicId; self.agreeDebaters.text = [NSString stringWithFormat:@"%@",topic.agreeDebaters]; self.disagreeDebaters.text = [NSString stringWithFormat:@"%@", topic.disagreeDebaters]; self.observers.text = [NSString stringWithFormat:@"%@", topic.observers]; } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; } @end </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload