1. Welcome to the new MacRumors forums. See our announcement and read our FAQ

Obj-C : declaring variables weirdness / noob release question

Discussion in 'Mac Programming' started by Palad1, Aug 28, 2008.

  1. macrumors 6502a

    Palad1

    #1
    Hello,

    My C is a bit rusty, and coming from .Net I am bound to do some stupid things... Could anyone explain why declaring pointers isn't allowed in a switch statement?

    Here's my code:

    Code:
    NSString* outerScope=nil;
    switch(myEnum){
      case kMyValue1:
        NSString* innerScope=@"InnerScope"; // Generates an error: unexpected token '*'
        outerScope=@"OuterScope"; // works
        for(int i=0;i<2;i++){ // works and also declares a variable in the statement
          NSLog(@"declared i and iterates over it... %d",i);
        }
    
        break;
      case kMyValue2:
        // and now for something completely different
        break;
    }
    
    So how come I cannot declare a pointer in my switch statement? I bet $DEITY is killing kittens when I try declaring variables in there, but I'm a bit lost here...

    Bonus question :
    Let's suppose I were to develop using a custom gui toolkit for an undisclosed embedded device, and would like to change the text of a IUBoutonArrondi by calling :
    Code:
    IUBoutonArrondi definirTitre:(NSString*) pourEtat:(int)
    Am I responsible for freeing the NSString* passed as an arg?

    Here's what I am currently doing:
    Code:
    NSString* str = [[NSString alloc] initWithCString("Bonjour Monde")];
    
    [leMagnifiqueBouton definirTitre:str pourEtat:0x1]; //assign the text to the widget
    
    // cleanup
    [str release]; // do I need to do this? What if str was assigned a const as in str=@"foo";
    
    I guess Java/.Net really spoiled me on the memory management side of programming.

    Thanks for your help, insight, and your surrender-monkey jokes.
     
  2. macrumors 6502

    #2
    Regarding the declaration-inside-switch case: Simply enclose the code in your case in a scope (curly braces). Otherwise, the NSString is declared in a sort of zombie-scope.

    When you pass in a pointer to a function, it is rare for the function to "take ownership" of it. So it's still yours.
     
  3. macrumors 6502a

    Palad1

    #3
    Thank you.

    Is the ownership transfer documented somewhere? In that case, I'd assume the method makes a copy of the value I am passing then.

    Cheers!
     
  4. macrumors 603

    whooleytoo

    #4
    If you create an object (e.g. via alloc & init, or copy) then it has a retained count of 1. You MUST call release (or autorelease) for it ever to be freed.

    If you call a function which creates an object and returns it, then you don't have to release it.

    There's an obvious problem here. If you write a function which creates (say) an NSString and returns it, how can you release it, and return it to the calling function. It would seem you can't do both. Well, you can. In this scenario, use autorelease. This says "I don't need this object any more, so if the caller needs it to hang around, it better retain it, or else it's going to be deleted".

    So, the guidelines are:
    If you create an object, YOU must release/autorelease it.
    If you create an object in a function and return it, you probably should autorelease it.
    If you call a function and it returns an object, you should retain it if you need it later on (i.e. outside the current scope).
    If you retain an object, you must release/autorelase it.

    Best of luck,
    Beer swilling top-o-the-mornin' monkey.
     
  5. macrumors 6502a

    Palad1

    #5
    Thanks whooleytoo.

    So my widget factory method should look like this:

    Code:
    - NSString* ToPaddy:(NSString*)french
    {
      NSString* paddy=nil;
      if([@"bonjour"] isEqualToString:french){
         paddy=@"Mornin' lad, let's get berco at the battle cruiser!";    
      }else{
         paddy= @"Wot?!?";
      }
      return [paddy autorelease];
    }
    
     
  6. Moderator

    robbieduncan

    Staff Member

    #6
    My understanding is that strings created with the @"My string here" construct as "special" and don't need to be autoreleased.

    Edit: see the documentation here. Strings created via the method are never deallocated...
     
  7. macrumors 603

    whooleytoo

    #7
    As Robbie says above - this is kind-of a special case I missed out on. If you just have a constant string as you have, you don't need to release it. You didn't create a new object via alloc or copy, so the rule about releasing it doesn't apply.

    If your code was as below, the autorelease would be needed. I've also corrected your strings, which were waaaay off! :)

    Code:
    - NSString* ToPaddy:(NSString*)french
    {
      NSString* paddy=nil;
      if([@"bonjour"] isEqualToString:french){
         paddy=[[NSString alloc] initWithString: @"Hey, how's the craic? Fancy one on the way home?"];    
      }else{
         paddy= [[NSString alloc] initWithstring: @"Wha?!?"];
      }
      return [paddy autorelease];
    }
    
     
  8. Moderator

    robbieduncan

    Staff Member

    #8
    That's still wrong. You mean

    Code:
      if([@"bonjour" isEqualToString:french])
    
     
  9. macrumors 603

    whooleytoo

    #9
    Oops, didn't spot that one.

    And I'm not sure that works either - can you send messages to a constant string? I have a feeling you can't. So it needs to be either:

    Code:
      if([[NSString stringWithString:@"bonjour"] isEqualToString:french])
    
    or

    Code:
      if([french isEqualToString:@"bonjour"])
    
     
  10. Moderator emeritus

    kainjow

    #10
    Yes you can. Constant strings are treated as normal NSString objects. You should treat them just the same as any other object in terms of memory management, even though like robbieduncan said they don't get released and are shared.
     
  11. Moderator

    robbieduncan

    Staff Member

    #11
    I think you can: they are just another object. If you can't the second is far better than the first: it doesn't create another object.

    For example if we had
    Code:
    NSString *constantLiteral = @"TryMe"
    if ([constantLiteral isEqualToString:@"OrMe"])
    {
    }
    
    that would look fine. I don't think inserting the variable really changes anything does it?
     
  12. macrumors 603

    whooleytoo

    #12
    Well, you learn something new every day. Problem is, I forget twice as much.
     
  13. macrumors 6502a

    Palad1

    #13
    Thanks for all the tips!

    I also learned that I shouldn't trust a Scotsman to teach me some Irish...

    Regarding the test on the string itself :
    Code:
    [@"bonjour" isEqualToString:french] 
    That's me thinking in .Net/Java and worrying about null reference exceptions...

    Now that Robbie shed some light on it, I think that this will also work:

    Code:
    NSString* who=nil;
    if([french isEqualToString:@"bonjour"]){
     // insert way-off string here
    }else{
      NSLog(@"Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.");
    }
    
    Cheers,
    Palad1
     
  14. Moderator

    robbieduncan

    Staff Member

    #14
    Not sure what you latest example is meant to show: you've declared a NSString* variable that is pointing at nothing (==nil), but you've not used it!

    But regardless note that in Object-C/Cocoa messaging nil should not crash the app, at least on it's own...
     
  15. Moderator emeritus

    kainjow

    #15
    But inserting a nil object into a dictionary or array will :)
     
  16. Moderator

    robbieduncan

    Staff Member

    #16
    Most certainly. Probably using one as a key for a dictionary too?
     
  17. macrumors 6502a

    Palad1

    #17
    Sorry, shouldn't be allowed anywhere near a keyboard after a pint.

    Appreciate the tips :)
     

Share This Page