开发者

Can someone explain to me why I "need" a retain statement in the following segment of code?

开发者 https://www.devze.com 2023-04-12 01:19 出处:网络
I believe in learning along the process and the following code segment is not very clear to me. I know that an alloc statement would increase the retain count however there are certain aspects of iOS

I believe in learning along the process and the following code segment is not very clear to me. I know that an alloc statement would increase the retain count however there are certain aspects of iOS development that are still very confusing to me.

Why do I need a : [jokesArray retain]; in the following code segment?

I have a jokesArray = [[NSArray alloc]init]; and from what I have read is enough to retain?

Can someone please explain in an easy to understand manner why that retain statement is needed? (Else the app crashes with a EXC_Bad_Access.

I have had some kind people try to explain but it has not worked. Any help will be greatly appreciated.

#import "JokesViewController.h"


@implementation JokesViewController

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)dealloc
{
    [super dealloc];
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super did开发者_StackOverflow中文版ReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{

    [super viewDidLoad];

    jokesArray = [[NSArray alloc]init];

    [self getJokes];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    [jokesArray release];

}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [jokesArray count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }





[[cell textLabel]setText:[[jokesArray objectAtIndex:0]objectForKey:@"text"]];    

 //   [[cell textLabel]setText:@"ok"];   

    return cell;
}

#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Navigation logic may go here. Create and push another view controller.
}


#pragma mark - Custom Functions

-(void) getJokes
{
    NSURL *url = [NSURL URLWithString:@"someurl"];
    __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
    [request setCompletionBlock:^{
        // Use when fetching text data
        NSString *responseString = [request responseString];

        NSDictionary *resultsDictionary = [responseString objectFromJSONString];
        jokesArray = [resultsDictionary allValues];

        [jokesArray retain];  //WHY DO I NEED THIS?


        [self.tableView reloadData];

        NSLog(@"%@", [jokesArray description]);

        // Use when fetching binary data
  //      NSData *responseData = [request responseData];
    }];
    [request setFailedBlock:^{
        NSError *error = [request error];

    }];
    [request startAsynchronous];
}

@end


You are leaking your previous NSArray allocation because in this part of the code:

 NSDictionary *resultsDictionary = [responseString objectFromJSONString];
    jokesArray = [resultsDictionary allValues];

    [jokesArray retain];

You are creating an NSDictionary and replacing whatever jokesArray was pointing to point to the data from NSDictionary that you just created. Also the data returned by NSDictionary was created using a convenience initialization method which means it will get released after a while thus the reason why you need to retain.

Since you are modifying the jokesArray variable directly the previously allocated NSArray doesn't get released when you replace it with the new object.


As far as I can tell, jokesArray does get retained on init.

However, since you have this line:

jokesArray = [resultsDictionary allValues];

You assign a complete different object to the variable, hence you retain a whole different object. I assume you would want something more like:

[jokesArray addObjectsFromArray:[resultsDictionary allValues]];

if its a mutable array. if not, you will have to to initalize a new one. In this case, I would probably only initialize jokesArray when needed.


You have this:

jokesArray = [[NSArray alloc]init];

Separately, you have this:

jokesArray = [resultsDictionary allValues];

The 2nd call, calling allValues, is allocating a brand new jokesArray. The one you'd already allocated is now lost (assuming jokesArray isn't a retained property) and you ought to release it before re-assigning via the allValues line.

The reason you need a 'retain' after the allValues call is because the memory allocated in allValues will be marked for autorelease. If you want that memory to stick around (and it appears you do), you need to retain it. Then your call to release in viewDidUnload has something to release, and your other references to jokesArray (e.g. the count call) have some memory to act against.

Switching to using a retained property will save you from all this hassle.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号