Make an array in Obj-C

Discussion in 'Mac Programming' started by gizabo, Apr 10, 2009.

  1. macrumors regular

    #1
    I want to make an array in obj c

    i need it to store strings. For example:

    *I like apple
    *Objective C is cool
    *My way or the Highway

    Thanks,
    Dan
     
  2. macrumors 68040

    lee1210

    #2
    this is a bit ambiguous. Do you want the "C way", with an array of char * pointing to null terminated arrays of characters, or do you want to do things the "Cocoa way" and store an arbitrary number of NSString objects in an NS(Mutable)Array?

    -Lee
     
  3. macrumors regular

    #3
    cocoa please :)
     
  4. macrumors regular

    #4
    i just need to know how to make an array (in cocoa) that stores whole sentances (or strings)
     
  5. macrumors 68040

    lee1210

    #5
    Code:
    #import <Foundation/Foundation.h>
    
    int main(int argc, char *argv[]) {
      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
      NSArray *myListOfStrings = [NSArray arrayWithObjects:@"My First String",@"My Second String",@"My Third String",@"My Fourth String",@"My Fifth String",nil];
      for(int x=0;x<[myListOfStrings count];x++) {
        NSLog(@"String %d is %@",x+1,[myListOfStrings objectAtIndex:x]);
      }
      [pool release];
      return 0;
    }
    
    This is one way to do it. You cannot change myListOfStrings, though, it is fixed(unmutable). You could use NSMutableArray instead if needed.

    @"abc" is the syntax for an NSString literal.

    References:
    NSString
    http://developer.apple.com/document...lasses/NSString_Class/Reference/NSString.html

    NSArray:
    http://developer.apple.com/document...lasses/NSArray_Class/Reference/Reference.html

    I was having trouble quickly finding the specific docs on NSString literals, so maybe someone else can post that.

    -Lee

    EDIT: I would far prefer the use of fast enumeration, but alas am still on 10.4, and wanted to make sure the code i posted compiled.
     
  6. macrumors regular

    #6
    Thanks for the reply again Lee! U have been a big help over the past few weeks


    but im getting an error:

     
  7. macrumors 68040

    lee1210

    #7
    with the code i gave you? if not, post your code.

    And you're welcome. =)

    -Lee
     
  8. macrumors regular

    #8
    well this is the code in my appcontroller.m file


    Code:
    #import "AppController.h"
    
    NSArray *myListOfStrings = [NSArray arrayWithObjects:@"Chullll ******",@"Big Kitchen? FAGOT!",@"Best sause ever. Cost $20",@"You should become a veggitarian",@"$400 BB GUNS!", @"Your TV sucks. Not HD!", @"Kar 98K with Double tap!", nil];
    
    @implementation AppController
    
    - (IBAction)buttonClicked:(id)sender
    {
    	[response setStringValue:[NSString stringWithFormat:@"I have been clicked"]];
    }
    
    @end
    
    

    lmao ignoore the strings... they are inside jokes with my friends
     
  9. macrumors 68040

    lee1210

    #9
    What are you wanting to do here? The problem is that you are asking the compiler to initialize a particular variable at compile time with a non-constant expression that can only be evaluated at run-time. You also don't use the NSArray anywhere, so it's not doing much for you.

    Also:
    Code:
    [NSString stringWithFormat:@"I have been clicked"]
    is equivalent to:
    Code:
    @"I have been clicked"
    except now there's a new autoreleased NSString that you don't really need.

    Finally... hm... just use test data if you don't want people to see potentially offensive epithets, even if they are meant as harmless inside jokes? I am battling to ignore it, but there is a real possibility that such jokes may be at the expense of a group of which someone who is helping you is a member.

    Back to the topic at hand... I would suggest initializing an NSArray in awakeFromNib, so it can be setup at runtime instead of compile time (you can't have an instance of an object at compile time).

    -Lee

    Edit: This is a decent reference for @"" NSString literals:
    http://developer.apple.com/documentation/Cocoa/Conceptual/Strings/Articles/CreatingStrings.html
     
  10. macrumors regular

    #10
    I am sorry Lee, i did not mean to offend you in anyway whatsoever.
    Im making this app for a friend of mine who has a friend who comments with everything by saying "******"

    I really did not mean to offend you, and i am sorry. Honestly, i support that group and i think they should have every right that other people do. Im sorry though, and i shouldnt of wrote that

    And ignoore
    Code:
    [NSString stringWithFormat:@"I have been clicked"]
    
    i was just using that so i can see if the image i clicked actually works.

    And im sorry, lol but i dont understand how to fix the problem... What code should i add?



    (PS im really sorry about that though, i did not mean to offend you)
     
  11. macrumors 68040

    lee1210

    #11
    I am not offended, i just wanted to point out that the potential is there.

    This was the first hit i found on tutorials that include awakeFromNib:, so it may not be the best:
    http://www.midgard-project.org/documentation/xcode_tutorial/

    In any event, you need to make a method with the signature:
    Code:
    -(void)awakeFromNib
    This will get called once, when the app starts. Here you can set up any of the data you need. You can declare your NSArray * as it is declared now, but do not initialize it there. Instead, put the code in awakeFromNib to initialize it. That way when the app starts, this array will be setup with the desired values, and can be used in subsequent method calls,etc..

    -Lee
     
  12. macrumors regular

    #12
    bleh! I still dont get it! I have never been good at reading and gathering information :mad:
     
  13. macrumors 68040

    lee1210

    #13
    In your AppController.m file, add a method:
    Code:
    -(void)awakeFromNib {
      myListOfStrings = [NSArray arrayWithObjects:@"String 1",@"String 2",@"String 3",@"String 4",@"String 5", @"String 6", @"String 7", nil];
    }
    
    And change the original declartion of myListOfStrings to just:
    Code:
    NSArray *myListOfStrings;
    
    -Lee
     
  14. macrumors regular

    #14
    Ahhh Lee, Lee, Lee... What would i do without you? :D


    Thanks man! Cya around!
     
  15. macrumors regular

    #15
    Lol wait one more thing! Sorry!

    Code:
    [response setStringValue:[NSString stringWithFormat:@"%@", myListOfStrings[random() % 8 + 1;]];
    

    Why doesnt that work? Im trying to change the label to one of my values in the array
     
  16. macrumors 6502a

    #16
    Well, before you go too far here, it seems as though you now have an NSArray declared in global scope which is very unusual for a Cocoa program and probably not what you wanted.

    And I don't think you retained the array, either. (or are you using GC?)

    If you need to keep the array around for a while, you probably want to create an instance variable in your AppController and then initialize that in awakeFromNib or just in your init as Lee as shown. Don't forget to retain it also (if you aren't using the garbage collector that is).
     
  17. macrumors 68040

    lee1210

    #17
    ah, quite right... should be in the @interface in AppController.h. And eddietr is right... i picked a method that returned something autoreleased because in my example the scope was very small. It would be better to alloc and initWithObjects:, then retain.

    In response to gizabo's last comment... you asked for the Cocoa way, and you got it =). You cannot access elements of an NSArray with the [] operator. Look at my original example, and the link I gave for NSArray to see how to properly get something out of the array at a particular index.

    Also, did you call randomize() before using random()? Also, you add 1, so the range of indicies is 1 to 8. NSArrays are, like C-style arrays, 0-based.

    I think you want something like:
    Code:
    [response setStringValue:[myListOfStrings objectAtIndex:(random()%8)]];
    -Lee
     
  18. macrumors regular

    #18
    AHHH IM SO CONFUSED! sorry im just out of it today! Here is my code:

    Code:
    #import "AppController.h"
    
    @implementation AppController
    
    - (void)awakeFromNib {
    	NSArray *myListOfStrings = [NSArray arrayWithObjects:@"s1",@"s2",@"s3",@"s4",
    								@"s5", @"s6", @"s7", @"s8", nil];
    
    }
    
    - (IBAction)buttonClicked:(id)sender
    {
    	[response setStringValue:[myListOfStrings objectAtIndex:(random()%8)]];
    }
    
    @end
    

    Code:
    #import <Cocoa/Cocoa.h>
    
    
    @interface AppController : NSObject {
    	
    	IBOutlet NSTextField *response;	
    	NSArray *myListOfStrings;
    
    }
    
    - (IBAction)buttonClicked:(id)sender;
    
    @end
    
    
     
  19. macrumors 68040

    lee1210

    #19
    Does it work? It looks pretty good to me. The only thing is, in awakeFromNib, add:
    Code:
    [myListOfStrings retain];
    randomize();
    
    The issue here is that you'll never send it a release... probably not a big deal here, but it's normally critical that these "match". you could technically put it in the dealloc of the AppController... but this is likely not to be called anyway.

    It also might be worth making something like:
    Code:
    -(NSString *)getRandomQuote
    {
      NSUInteger myPos = random()%[myListOfStrings count];
      return [myListOfStrings objectAtIndex:myPos];
    }
    
    Then in buttonClicked instead of what's there now:
    Code:
    [response setStringValue:[self getRandomQuote]];
    
    -Lee
     
  20. macrumors regular

    #20
    ok well here is my code
    Code:
    @implementation AppController
    
    - (void)awakeFromNib {
    	NSArray *myListOfStrings = [NSArray arrayWithObjects:@"s1",@"s2",@"s3",@"s4",
    								@"s5", @"s6", @"s7", @"s8", nil];
    
    	[myListOfStrings retain];
    	randomize();
    	
    }
    
    -(NSString *)getRandomQuote
    {
    	return [myListOfStrings objectAtIndex:(random()%[myListOfStrings count])];
    }
    
    - (IBAction)buttonClicked:(id)sender
    {
    	[response setStringValue:[self getRandomQuote]];
    }
    
    @end
    

    and look at the warnings iget

     
  21. macrumors 68040

    lee1210

    #21
    OK... so
    Code:
    #include <stdlib.h>
    for random() and randomize(), i had assumed incorrectly that was already done...

    And change the first line of awakeFromNib to:
    Code:
    myListOfStrings = [NSArray arrayWithObjects:@"s1",@"s2",@"s3",@"s4",
    								@"s5", @"s6", @"s7", @"s8", nil];
    
    I missed that the last time you posted your code. You don't want to declare a new variable, just assign the pointer to the existing ivar. In buttonClicked and getRandomQuote, they are looking at the uninitialized ivar called myListOfStrings, not the one local to awakeFromNib right now, hence the incorrect behavior.

    -Lee
     
  22. macrumors regular

    #22
    thanks so much! but i feel lost about how this works... ill study this and look it up so i understand 100% how it works

    THanks!
     
  23. macrumors 68040

    lee1210

    #23
    So it does work now, you just don't know how?

    I would look at the references I sent for each of the methods used:
    For NSString the only thing that was used was @"" NSString literal notation to generate the strings to place in the array. Look at the String Programming Guide linked above as it discusses this notation a bit, and what sort of thing that actually gets you (an NSString * that points to an "immortal" NSString instance).

    NSControl's setStringValue: method:
    http://developer.apple.com/DOCUMENT...apple_ref/occ/instm/NSControl/setStringValue:

    NSArray
    initWithObjects:
    http://developer.apple.com/DOCUMENT.../apple_ref/occ/instm/NSArray/initWithObjects:

    objectAtIndex:
    http://developer.apple.com/DOCUMENT...#//apple_ref/occ/instm/NSArray/objectAtIndex:

    I may have mistaken about the need for randomize(). It's always been in my head that it's needed, but maybe the BSD versions don't require it? Or you need to call srandom instead? You can read the manpage for random() by typing:
    man random
    from the terminal.

    That's all of the things used, other than the connections in interface builder.

    Since you're just getting started, the memory management guide is a must, too:
    http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

    -Lee
     
  24. macrumors newbie

    #24
    Thanks Lee. Your replies were really helpful to me too.
    Especially, my code was working, but I was getting the following unrecognized selector error on console from a tableView class:

    2009-05-14 17:24:02.335 ImageInTable[25752:10b] Data is Two
    2009-05-14 17:24:02.337 ImageInTable[25752:10b] Data is Two
    ...
    2009-05-14 17:24:02.402 ImageInTable[25752:10b] *** -[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x13ab00
    2009-05-14 17:24:02.402 ImageInTable[25752:10b] *** -[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x13ab00
    ...

    Turned out to be a problem with retain count.
    Your point on [myListOfStrings retain] fixed it.

    I was curious as to why the code executed for (say) 10 rows and then generated the error.
    What would have prompted Cocoa to release the array at a particular point?
     
  25. macrumors 68040

    lee1210

    #25
    In looking for a reference on this, I was hoping to find something about the run loop/event loop that discussed this a bit, but instead came across this stack overflow thread:
    http://stackoverflow.com/questions/6578/understanding-reference-counting-with-cocoa-objective-c

    There is a pretty good explanation of what's going on there. Basically at some point (and it's not up to you) autoreleased things will be reclaimed. If you need something for a "long time" you need to say so by sending a retain. It looks like your memory got released before you were ready, then a new member of the NSString class cluster got created there and started getting your messages.

    -Lee
     

Share This Page