nsmutablearray problem

Discussion in 'iPhone/iPad Programming' started by medasmx, Jul 13, 2011.

  1. macrumors member

    Joined:
    Nov 9, 2008
    #1
    interface file…

    Code:
        IBOutlet UILabel*label;
        NSMutableArray*myArray;
        IBOutlet UITextField*someText;
    }
    -(IBAction)programLabel:(id)sender;
    -(IBAction)addText:(id)sender;
    
    implementation file...

    Code:
    - (id)init {
    	if (self == [super init]) {
    		myArray = [[NSMutableArray alloc] initWithObjects: nil];
            myArray = [NSMutableArray arrayWithCapacity:50];
    	}
    	return self;
    }
    
    -(IBAction)programLabel:(id)sender{
    
        label.text=[NSString stringWithFormat:@"%@",[myArray objectAtIndex:0]];
    }
    
    -(IBAction)addText:(id)sender{
        
        [myArray insertObject:[NSString stringWithFormat:@"%@", someText.text] atIndex:[myArray count]];    
    
        NSLog(@"%@",[myArray objectAtIndex:0]);
    }
    
    Logging the contents of the mutableArray, myArray, it is null. If you initialize the mutable array within the action "addText" the array is not null, but then it cannot be used in the action "programLabel". As a second exercise, I tried to create a second mutable array locally (within addText), then adding its contents to myArray, using arrayWithArray, etc, but that hasn't worked either. I have google'ed extensively, and have been surprised not to find a sample addressing this online or in books, because it seems like it would be used commonly. In any case, any help is appreciated.
     
  2. macrumors 68040

    Joined:
    Apr 22, 2005
    #2
    The problem is the way in which you are creating the array, and the fact that you probably need to read up on memory management in Objective-C.

    One of these two lines in your init is redundant:

    Code:
    myArray = [[NSMutableArray alloc] initWithObjects: nil];
    myArray = [NSMutableArray arrayWithCapacity:50];
    
    because both of them return a new array. You can use either one, but there is an essential difference between them when it comes to memory management that you must understand.

    The first line gives you an array that your class now owns with a retain count of 1. That means this array will be valid as long as your class is, assuming that you release it in your class' dealloc method and not somewhere earlier.

    The second line gives you an autoreleased array that you must retain if you want it to exist as long as your class does. Since you do not do this currently, myArray gets deallocated some time after init returns and before you have a chance to do anything else with the array.

    If terms like retain, release, and autorelease aren't familiar to you, you should read the memory management in Objective-C guide in Apple's docs and/or other web tutorials on the subject.
     
  3. macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #3
    In addition to the reply above, there's a coding error hightlighted in red above. It should be =, not ==.
     
  4. macrumors 68040

    Joined:
    Apr 22, 2005
    #4
    Good catch!
     
  5. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #5
    Since Xcode 4.x it gives warnings when you do that, and suggests to do == instead of =.
    Just saying what I have noticed ;p
     
  6. macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #6
    Skills developed while tutoring (being a TA) to 1st year students, and from coding MARC library catalogue records. :)


    The idiom should be either:
    Code:
    self = [super init];
    if (self) {
      // ...
    }
    return self;
    or (notice the double parentheses):
    Code:
    if ((self = [super init])) {
      // ...
    }
    return self;
     
  7. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #7

    Myself, I use the first one, Have used the second too.
    Can't recall when Xcode is trying to replace the = with ==, i'll try to figure it out agian and let you know x)
     
  8. macrumors 68040

    Joined:
    Apr 22, 2005
    #8
    Well, Xcode knows that most of the time, == is in fact the appropriate operator to use in the conditional part of an if statement rather than =. It will give you that warning if you use = without putting the whole assignment in ().
     
  9. medasmx, Jul 14, 2011
    Last edited: Jul 14, 2011

    thread starter macrumors member

    Joined:
    Nov 9, 2008
    #9
    update

    interface…I don't use NSMutableArray as a property

    Code:
        NSMutableArray*myArray;
    
    implementation…

    Code:
    - (id)init {
    	self=[super init];
    	myArray=[[NSMutableArray alloc]init];
    	return self;
    }
    
    -(IBAction)programLabel:(id)sender{
    	NSLog(@"%@",[myArray objectAtIndex:0]);
    	label.text=[NSString stringWithFormat:@"%@",[myArray objectAtIndex:0]];
    }
    
    -(IBAction)addText:(id)sender{
        
        	NSString*someString=[NSString stringWithFormat:@"%@",someText.text];
    	
    	myArray=[[NSMutableArray alloc]initWithObjects:someString,nil];
    	
    	NSLog(@"%@",someString);
    	NSLog(@"%@",[myArray objectAtIndex:0]);	
    }
    
    What I was looking for was the following. Declare a mutableArray in the interface, then input from the text file and add to that array in the implementation. Finally, display different elements from the array as labels. The downfall with the above is that I would like to be adding to the array (myArray) each time. What I have is creating an array with one element. Will keep working…

    Appreciate comments from late last night and earlier today. Thanks.

    later post--

    This also works…

    Code:
    -(IBAction)addText:(id)sender{
        
        	NSString*someString=[NSString stringWithFormat:@"%@",someText.text];
    	NSMutableArray*someArray=[[[NSMutableArray alloc]init]autorelease];
    	someArray=[NSMutableArray arrayWithArray:myArray];
    	[someArray addObject:someString];
    	NSLog(@"%@",[someArray objectAtIndex:0]);
    }
    
    I then want to make myArray empty, and set it equal to a copy of someArray. When I tried that it didn't work. Thanks again for any advice.
     
  10. macrumors 68040

    Joined:
    Apr 22, 2005
    #10
    You are still creating waaay too many arrays. You should only need to initialize the array in your class' init method. Your second version of addText also still has the same problem as your original init method where you are redundantly creating the array twice in a row, and not doing appropriate memory management with either.

    I would suggest stepping back and reading some more basic Objective-C tutorials and/or examples.
     
  11. macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #11
    It's a bad habit not to check self before attempting to initialize instance variables. I won't get into to it, just use one of the two idioms I posted above.

    Are you using this technique as an explicit defensive programming technique? Or do you not understand what this codes does?

    Code:
    -(IBAction)addText:(id)sender{
        
        	NSString*someString=[NSString stringWithFormat:@"%@",someText.text];
    	NSMutableArray*someArray=[[[NSMutableArray alloc]init]autorelease];
    	someArray=[NSMutableArray arrayWithArray:myArray];
    	[someArray addObject:someString];
    	NSLog(@"%@",[someArray objectAtIndex:0]);
    }
    
    This is incredibly inefficient. You start by creating a new string by copying an existing string (may be valid, but I doubt you've done it deliberately). Then you create an empty mutable array, which you promptly discard in the next line. Then you copy an existing mutable array, add an object to it, and then forget it.

    All you needed was:
    Code:
    -(IBAction)addText:(id)sender{
        [myArray addObject:someText.text];
    }
    
    It really seems you have little understanding of what you're actually doing. I would strongly advise going back to basics and (re-)learning fundamental programming generally, and object-oriented programming more specifically.

    Are you reading (or have you read) any books on Objective-C? If not, what resources are you using (or have you used)?
     
  12. macrumors 68040

    Joined:
    Apr 22, 2005
    #12
    As an additional tip, please please please put a space between a variable's type and its name when you are declaring it.

    Seeing

    Code:
    UILabel*label;
    
    will make most programmers want to scream.

    Either of these two is acceptable

    Code:
    UILabel *label;
    UILabel* label;
    
    although the first is usually preferred because if you are declaring several pointer (i.e. *) variables in one statement, it -must- be done like this:

    Code:
    UILabel *label1, *label2, *label3;
    
    where there is one * for each variable.
     
  13. macrumors 6502a

    Joined:
    Feb 26, 2011
    Location:
    Las Vegas, NV
    #13
    THANK YOU! Glad someone said something.
     

Share This Page