Friday, April 15, 2011

Problem to populate a Tableview on iPhone

Code N°1:

NSMutableArray *arrayTmp = [[NSMutableArray alloc] initWithObjects:nil];

[arrayTmp addObject:@"line 1" ];
[arrayTmp addObject:@"line 2" ];

self.list = arrayTmp;
[self.tableView reloadData];
[super viewDidLoad];
[arrayTmp release];

Code N°2:

NSMutableArray *arrayTmp = [[NSMutableArray alloc] initWithObjects:nil];

NSString *fieldName = [[NSString alloc] init];
fieldName = [NSString stringWithFormat:@"%@",@"Ligne1"];
[arrayTmp addObject:(NSString *) fieldName];
[arrayTmp addObject:@"line 2" ];

self.list = arrayTmp;
[self.tableView reloadData];

[super viewDidLoad];
[arrayTmp release];

*Codes N°1 & N°2 do exactly the same job: they populate a tableview. My problem is with the code N°2:he displays the tableView but if I move the tableView with the finger, the iphone freeze. The Debugger shows the following message: "GDB:Program receive signal: "EXC_BAD_INSTRUCTION". I don't see what it is wrong. Has someone an idea of the problem ? Thank you in advance.*

From stackoverflow
  • My guess would be that self.list does not retain the array, and when filling the table view you add references to the strings in that list. Your property should look like;

    @property (retain) NSArray* list;
    

    This is not a problem in the first example because the strings are literal - e.g. they are embedded in your program and are never deallocated.

    The second example creates a temporary string, and although its reference is incremented when added to the array it will later deallocated and destroyed when the array is released.

    Also this code;

    NSString *fieldName = [[NSString alloc] init];
    fieldName = [NSString stringWithFormat:@"%@",@"Ligne1"];
    

    Is going to result in a memory leak. You are allocating a new string, then changing the value in the pointer to be the result of the stringWithFormat call. If you wish fieldname to persist then the correct code would be;

    NSString *fieldName = [[NSString stringWithFormat:@"%@",@"Ligne1"] retain];
    
  • Thank you for your very good advices. As you suggest, I retain the array in my @property:

      @property (retain) NSArray *list;
    

    If in my code I put:

     NSString *fieldName = [[[NSString alloc] initWithString: @"line 1"] retain];
    [arrayTmp addObject:fieldName];
    [arrayTmp addObject:@"line 2" ];
    

    it's working!

    But if I put:

    NSString *fieldName = [[[NSString alloc] initWithString: [NSString stringWithFormat: @"line 1"] ] retain];
    [arrayTmp addObject:fieldName];
    [arrayTmp addObject:@"line 2" ];
    

    it's display well the tableview but if I move the tableView 2 or 3 times with the finger, the iphone freeze.And unfortunately, I need to use stringWithFormat & stringWithUTF8String in order to populate my tableView from a database.

    The error is still "EXC_BAD_ACCESS". But I don't know how to perform a backtrace. The Debugger shows:

    0 0x300c8c18 in objc_msgSend

    1 0x30b524dc in -[UILabel text]

    2 0x30c07b44 in -[UITableViewCell layoutSubviews]

    3 0x30a74020 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]

    4 0x31dd20f0 in -[CALayer layoutSublayers]

    5 0x31dd2000 in CALayerLayoutIfNeeded

    6 0x31dd1774 in CAContextCommitTransaction

    7 0x31dd143c in CATransactionCommit

    8 0x3026a0ec in __CFRunLoopDoObservers

    9 0x30269920 in CFRunLoopRunSpecific

    10 0x30269326 in CFRunLoopRunInMode

    11 0x31563e60 in GSEventRunModal

    12 0x30a4feb8 in -[UIApplication _run]

    13 0x30a5961c in UIApplicationMain

    14 0x000020bc in main at main.m:14

    asm obj_msgSend 0x300c8cc04:1 0x300c8c04 <+0000> teq r0, #0 ; 0x0

    0x300c8c08 <+0004> moveq r1, #0 ; 0x0

    0x300c8c0c <+0008> bxeq lr

    0x300c8c10 <+0012> stmdb sp!, {r3, r4, r5, r6}

    0x300c8c14 <+0016> ldr r4, [r0]

    0x300c8c18 <+0020> ldr r5, [r4, #8]

    0x300c8c1c <+0024> ldr r6, [r5]

    0x300c8c20 <+0028> add r3, r5, #8 ; 0x8

    0x300c8c24 <+0032> and r5, r6, r1, lsr #2

    0x300c8c28 <+0036> ldr r4, [r3, r5, lsl #2]

    0x300c8c2c <+0040> teq r4, #0 ; 0x0

    0x300c8c30 <+0044> add r5, r5, #1 ; 0x1

    0x300c8c34 <+0048> beq 0x300c8c54

    0x300c8c38 <+0052> ldr ip, [r4]

    0x300c8c3c <+0056> teq r1, ip

    0x300c8c40 <+0060> and r5, r5, r6

    0x300c8c44 <+0064> bne 0x300c8c28

    0x300c8c48 <+0068> ldr ip, [r4, #8]

    0x300c8c4c <+0072> ldmia sp!, {r3, r4, r5, r6}

    0x300c8c50 <+0076> bx ip

    0x300c8c54 <+0080> ldmia sp!, {r3, r4, r5, r6}

    0x300c8c58 <+0084> b 0x300c8c5c

  • Here's how you should use code 2

    NSString *fieldName = [[NSString alloc] initWithString:@"Ligne1"];
    NSMutableArray *arrayTmp = [NSMutableArray arrayWithObjects:fieldName, @"line2", nil]; //I would suggest using @"Ligne1" instead of fieldName if possible
    
    self.list = [arrayTmp retain]; //This will make sure even after releasing arrayTmp, list is not affected
    [self.tableView reloadData];
    
    [arrayTmp release];
    
  • Thank you for your replies.

    At the end, I resolve my problem by:

    -adding a "retain" to my NNString fieldName

    -removing a "release" on a variable in the tableView method "cellForRowAtIndexPath"

    Thank again for your helpfull support !

0 comments:

Post a Comment

Note: Only a member of this blog may post a comment.