static NSString Array from a file in a constant.h file

Discussion in 'iOS Programming' started by roeik, Feb 5, 2010.

  1. roeik macrumors member

    Joined:
    Dec 25, 2008
    #1
    Hi Guys,

    I am trying to figure out what would be the best way to have a constant array accessible from my entire project.

    I currently have a constant.h file in my project, where i define all the constants and use it throughout the project. (like in UICatalog).

    Would it be possible to add a constant array there initialized from a file? The file is just a txt file with one word in each line.

    thanks for your help.
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Personally (and I already know people will say this is a bad idea) I'd create a singleton class that encapsulates the data. The first time the shared instance is requested I'd load and parse the data from a text file into an array.
     
  3. roeik thread starter macrumors member

    Joined:
    Dec 25, 2008
    #3
    well, is there a way to initialize it in the constant.h file?

    Also what would be the proper statement to to declare an array of NSStrings?
    I have 30 values so I guess I can just type them in the code, but it will be way easier if I can just initialize it from a file.

    Thanks for your help.
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    As I said I would make a proper object: .h and .m files. You can create an array of pointers to any Objective-C object type using normal C syntax, although the more Objective-C/Cocoa way would be to use an NSArray which, if the content is truly static, you can initialise using the obvious method in the documentation.
     
  5. roeik thread starter macrumors member

    Joined:
    Dec 25, 2008
    #5
    right, this is how I normally initialize an array in the .m file in code.
    But is there a way to just declare a const array in .h files? (for my case in constant.h file).

    In c for example, I would just declare int list[5] = {1,2,3,4,5};

    But I can't just put the arrayWithObjects function in the constants.h file.
     
  6. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #6
    What prevents you doing:
    Code:
    NSString *strings[5] = {@"I",@"can",@"use",@"C",@"constructs"};
    
    This is not an NSArray, but it is a (non const) array of NSStrings. I made it non-const as your int example is non-const.
     
  7. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #7
    How often does your file of 30 strings change? If the answer is "Never", then a simple copy and paste of the text into a header file, followed by some repetitive but simple editing should suffice. The result will be a header file with the strings in source-code form (quoted, with commas, etc.).

    If your file of 30 strings changes regularly, then you should consider a production tool that transforms the original text file into the form of a source file.

    For example, consider this list of words:
    Code:
    sun
    shining
    sea
    with
    might
    
    Next, consider what the source form of the array would be:
    Code:
    NSString *strings[] = {
    @"sun",
    @"shining",
    @"sea",
    @"with",
    @"might"
    };
    
    To get that form, we need to add the variable declaration and opening brace (prologue), then list of @-quoted words, then add the trailing brace and semicolon (epilogue).

    Any programming language could be used to produce the source form from the original text, but the 'awk' command is designed for just such tasks.

    The middle part, listing @-quoted words, can be done like this:
    Code:
    awk '{ printf "@\"%s\",\n", $0 }' words.txt >wordsAsSource.m
    
    We could also use awk to produce the prologue and epilogue, but I'll use 'echo' instead. The whole sequence of commands is then:
    Code:
    echo >wordsAsSource.m '#import <Foundation/Foundation.h>'
    echo >>wordsAsSource.m 'NSString *strings[] = {'
    awk >>wordsAsSource.m '{ printf "@\"%s\",\n", $0 }' words.txt
    echo >>wordsAsSource.m '};'
    
    You can copy and paste that into Terminal, or you can make a shell script, or you can add a Shell Script Build Phase to your Xcode project.
     
  8. roeik thread starter macrumors member

    Joined:
    Dec 25, 2008
    #8
    well, this wouldn't compile on .h file. But if you add "static const" before it will.

    Code:
    static const NSString *strings[3] = {@"value",@"value",@"value"};
     
  9. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #9
    It was probably left as an exercise for the interested reader.


    Also, you might want to read up on exactly what the static keyword does. As given, if you include the .h file in different source files, then each file that includes it gets its own private copy of the array. If one of your goals is to not duplicate things unnecessarily, then using static will work against that goal.

    wordy.h:
    Code:
    #import <Foundation/Foundation.h>
    static const NSString *strings[] = 
      { @"sun", @"shining", @"sea", @"with", @"might", };
    
    wordy.m:
    Code:
    #import "wordy.h"
    
    extern NSString ** wordy2();
    
    int main (int argc, const char * argv[])
    {
      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
      
      NSLog( @"main strings: %p", strings );
      NSLog( @"wordy2 strings: %p", wordy2() );
      
      [pool drain];
      return 0;
    }
    
    wordy2.m:
    Code:
    #import "wordy.h"
    
    NSString ** wordy2()
    {  return strings;  }
    
    Commands & output:
    Code:
    gcc wordy.m wordy2.m -framework Foundation
    ./a.out
    2010-02-05 15:09:23.656 a.out[21710] main strings: 0x3010
    2010-02-05 15:09:23.657 a.out[21710] wordy2 strings: 0x3024
    
     
  10. roeik thread starter macrumors member

    Joined:
    Dec 25, 2008
    #10

    I just used your suggestions with the awk command. Works like magic!!!
    Thanks!

    Since my list of values will probably not't change very often i don't need to make a shell script build phase, but it's great to know this option exists.

    Thank you for your help.
     

Share This Page