array of strings in a constant with #define - objective c - objective-c

I need a array of strings in a constant. is a good idea to use #define?
For example:
#define rows [NSArray arrayWithObjects: #"NameRowA",#"NameRowB",#"NameRowC", nil]
#define KEY_ROWA [columnas objectAtIndex:0]
#define KEY_ROWB [columnas objectAtIndex:1]
#define KEY_ROWC [columnas objectAtIndex:2]
I need to access to the array of strings and the elements of that array.
I have read, (i don´t know if is true) with this way it is created a new NSArray when it is used, I suppose then the array is released, so I think this is good because you only use that part of memory when you need it.

Use a singleton, it's just a couple of lines of code.
All you need is a static singleton, and a static method for retrieving it (and settings it once).
Your .m file should contain this:
#implementation MyClass
static NSArray *mySingletonArray; // this will be your array
+ (NSArray *)mySingletonArray // this is the static method for accessing your array
{
if (nil == mySingletonArray) {
mySingletonArray = [NSArray arrayWithObjects:#"firstString", #"secondString", nil];
}
return mySingletonArray;
}
Acquire what you need from you array using the static access method [MyClass mySingletonArray], e.g.
NSLog("%#", [[MyClass mySingletonArray] objectAtIndex:0]);

I don't think you want to use #define for this.
In your example, there is no constant array of strings made with this code. Every single time rows is used in your code, a new NSArray is going to be allocated. Also, KEY_ROWA refers to columnas, but that isn't in the rows define. I assume you have something like this
NSArray *columnas = rows;
There is really no difference between that and
NSArray *columnas = [NSArray arrayWithObjects: #"NameRowA",#"NameRowB",#"NameRowC", nil];
But the second line is a lot more obvious. The same is true with KEY_ROWA -- the objectAtIndex call would be more obvious and the macro doesn't get you anything.
I'm not sure what you need exactly, but if you need a shared constant array of strings inside of one class, you could declare it as + instead of - at the beginning, and allocate it once (this is a class variable as opposed to an instance variable). More info here:
How do I declare class-level properties in Objective-C?

Related

Constant value of NSString representation

I have a PList where I load a couple of rows of data in a dictionary. I want to add the a line like
<key>StandardValue</key>
<string>STANDARDVALUEFORCERTAININSTANCE</string>
Now when I read out the values I get a NSString. How can I get the value of the constant that I previously defined with
#define STANDARDVALUEFORCERTAININSTANCE 123
Is there a way to get the constant representation of a string? So essentially to parse it?
What you want to do isn't exactly possible. The constants created with #define only exist at compile-time, and at run time there is no way to access them by name - they have been converted to the constant value already.
One alternative that might exist is to define a number of methods that return constant values, say in a Constants class. Then, at run time, load the name of the method from the plist and call it using NSSelectorFromString() and performSelector:.
However, a possible issue with this is that for safety with performSelector: you'd have to rewrite all your constants as Objective-C objects (since performSelector: returns type id). That could be quite inconvenient.
Nevertheless, here is an example implementation of the Constants class:
#implementation Constants : NSObject
+ (NSNumber *)someValueForACertainInstance
{
return #123;
}
#end
And example usage:
NSDictionary *infoDotPlist = [[NSBundle mainBundle] infoDictionary];
NSString *selectorName = infoDotPlist[#"StandardValue"];
SEL selector = NSSelectorFromString(selectorName);
NSNumber *result = [Constants performSelector:selector];
And how the selector name would be stored in the info plist:
<key>StandardValue</key>
<string>someValueForACertainInstance</string>
You can't do it this way. I suggest a nice alternative: KVC.
You declare this variable as class instance:
#property (nonatomic,assign) int standardValueForCertainInstance;
Then you get the value with valueForKey:
NSString* key= dict[#"StandardValue"];
int value= [[self valueForKey: key] intValue];

How to fill NSArray in compile time?

In Objective-C, how to do something like is
int array[] = {1, 2, 3, 4};
in pure C?
I need to fill NSArray with NSStrings with the smallest overhead (code and/or runtime) as possible.
It's not possible to create an array like you're doing at compile time. That's because it's not a "compile time constant." Instead, you can do something like:
static NSArray *tArray = nil;
-(void)viewDidLoad {
[super viewDidLoad];
tArray = [NSArray arrayWithObjects:#"A", #"B", #"C", nil];
}
If it's truly important that you have this precompiled, then I guess you could create a test project, create the array (or whatever object) you need, fill it, then serialize it using NSKeyedArchiver (which will save it to a file), and then include that file in your app. You will then need to use NSKeyedUnarchiver to unarchive the object for use. I'm not sure what the performance difference is between these two approaches. One advantage to this method is that you don't have a big block of code if you need to initialize an array that includes a lot of objects.
use this
NSArray *array = [NSArray arrayWithObjects:str1,str2, nil];
As far as i understand you need a one-dimentional array
You can use class methods of NSArray.. For instance
NSString *yourString;
NSArray *yourArray = [[NSArray alloc] initWithObjects:yourString, nil];
If you need more, please give some more detail about your issue
Simple as that: NSArray<NSString*> *stringsArray = #[#"Str1", #"Str2", #"Str3", ...]; Modern ObjectiveC allows generics and literal arrays.
If you want shorter code, then NSArray *stringsArray = #[#"Str1", #"Str2", #"Str3", ...];, as the generics are optional and help only when accessing the array elements, thus you can later in the code cast back to the templatized array.

Is there any way to specify the class of objects of a NSMutableArray?

Im having the following problem:
I've made a NSMutableArray "array" that is going to contain objects of a class named "Class". At the start that array should be empty and it must be filled during the program's execution.
As I never actually told the compiler that my NSMutableArray will be holding elements of the class Class, when I try to write the appropriate methods the compiler wont let me do it.
This is my first experience on Objective-C and iPhone development. I used to code in C/C++ where I declared my arrays in the following way:
Class array[NUMBEROFELEMENTS];
Is there any way to do this in Objective-C?
Thanks!
The truth is that is doesn't matter to the NSMutableArray what type of object it is. NSMutableArray simply stores pointers to all the objects they contain, or reference.
The trick is when you pull the object back out of the array you need to create a new pointer based on the appropriate type:
MyObject *myObject = [myArray objectAtIndex:0];
Then you can use the object however you like:
[myObject doThatThingWithThisValue:10];
Or whatever you need.
Arrays in Objective-C Cocoa are objects (as well as other collections, sets, dictionaries). Arrays can contain references to objects of any type, so the type for the array is simply NSArray, NSMutableArray, etc...
Since they are objects, you can send them messages to manipulate their content.
I suggest you take a look at Apple's excellent Collections Programming Topics, which explain the rudiments of collections.
Here is a quick example :
// two objects of different types
NSNumber *n = [NSNumber numberWithInteger:10];
NSString *s = #"foo";
// alloc/init a new mutable array
NSMutableArray *a = [NSMutableArray arrayWithCapacity:10];
// add an object
[a addObject:n];
[a addObject:s];
// array a now contains a NSNumber and a NSString
Well, you can still have C-style arrays in Objective-C.
However, the characteristics of Objective-C (some people will call it strength, other will call it weakness) is that it has dynamic typing of objects and dynamic dispatch.
It has NSArray and NSMutableArray which are not specialized for the certain class. It can store objects of non-compatible classes.
You can use the following idiom: [obj isMemberOfClass: [Class type]] to make sure an array element is of the desired type and then cast to Class*.
You can also use for-each loop (aka Fast Enumeration):
NSMutableArray* array = //... initialize your array
for (Class* elm in array) {
elm.your_property = 10;
}

One problem of NSMutableArray

the code is:
typedef struct _Package
{
char* data;
int dataLen;
}Package;
Package *pack=(Package *)malloc(sizeof(pack));
pack->dataLen = 10;
pack->data = (char *)malloc(10);
strcpy(pack->data,"hellohello");
NSMutableArray *lstPack = [[NSMutableArray alloc] init];
[lstPack addobjec:pack];
when the program goto [lstPack addobject:pack],it cann't go on.
If you know the reason,please tell me。
Thank you!
You can add to obj-c containters (including NSMutableArray) only obj-c objects. To add a c-structure to array you can wrap it to NSValue object:
[lstPack addObject:[NSValue valueWithPointer:pack]];
Later you access stored value:
Package* pack = (Package*)[[lstPack objectAtIndex:i] pointerValue];
Note also that you possibly have a typo in that line - method name is incorrect.
“… the result is that the p->data is nil …” — perhaps because of pack->dataLen = (char *)malloc(10);
I think, you wanted to do pack->data = (char *)malloc(10); instead?
Greetings
You can create a CFMutableArray instead which can handle arrays of arbitrary objects, and you can use it as you would an NSMutableArray (for the most part).
// create the array
NSMutableArray *lstPack = (NSMutableArray *) CFArrayCreateMutable(NULL, 0, NULL);
// add an item
[lstPack addObject:pack];
// get an item
Pack *anObject = (Pack *) [lstPack objectAtIndex:0];
// don't forget to release
// (because we obtained it from a function with "Create" in its name)
[lstPack release];
The parameters to CFArrayCreateMutable are:
The allocator to use for the array. Providing NULL here means to use the default allocator.
The limit on the size of the array. 0 means that there is no limit, any other integer means that the array is only created to hold exactly that many items or less.
The last parameter is a pointer to a structure containing function pointers. More info can be found here. By providing NULL here, it means that you don't want the array to do anything with the values that you give it. Ordinarily for an NSMutableArray, it would retain objects that are added to it and release objects that are removed from it¹, but a CFMutableArray created with no callbacks will not do this.
¹ The reason that your code is failing is because the NSMutableArray is trying to send retain to your Pack struct, but of course, it is not an Objective-C object, so it bombs out.

Change the values within NSArray by dereferencing?

I've come across a problem related to pointers within arrays in objective-c.
What I'm trying to do is take the pointers within an NSArray, pass them to a method, and then assign the returned value back to the original pointer(the pointer which belongs to the array).
Based on what I know from C and C++, by dereferencing the pointers within the array, I should be able to change the values they point to... Here is the code I'm using, but it is not working (the value phone points to never changes based on the NSLog output).
NSArray *phoneNumbers = [phoneEmailDict objectForKey:#"phone"];
for (NSString* phone in phoneNumbers) {
(*phone) = (*[self removeNonNumbers:phone]);
NSLog(#"phone:%#", phone);
}
And here is the method signature I am passing the NSString* to:
- (NSString*) removeNonNumbers: (NSString*) string;
As you can see, I am iterating through each NSString* within phoneNumbers with the variable phone. I pass the phone to removeNonNumbers:, which returns the modified NSString*. I Then dereference the pointer returned from removeNonNumber and assign the value to phone.
As you can tell, I probably do not understand Objective-C objects that well. I'm pretty sure this would work in C++ or C, but I can't see why it doesn't work here! Thanks in advance for your help!
Yeah, that's not going to work. You'll need an NSMutableArray:
NSMutableArray * phoneNumbers = [[phoneEmailDict objectForKey:#"phone"] mutableCopy];
for (NSUInteger i = 0; i < [phoneNumber count]; ++i) {
NSString * phone = [phoneNumbers objectAtIndex:i];
phone = [self removeNonNumbers:phone];
[phoneNumbers replaceObjectAtIndex:i withObject:phone];
}
[phoneEmailDict setObject:phoneNumbers forKey:#"phone"];
[phoneNumbers release];
You can't dereference Objective-C object variables. They are always pointers, but you should treat them as though they're atomic values. You need to mutate the array itself to contain the new objects you're generating.
NSArray is not a C/C++ style array. It's an Objective-C object. You need to use the instance methods of the NSArray class to perform operations on it.
In Objective-C you never "dereference" an object pointer to set its value.
Also, you're using what is called Fast Enumeration, which does not allow mutation.
You can also use enumerateObjectsUsingBlock:.
NSArray *array = [NSArray array];
__block NSMutableArray *mutableCopyArray = [array mutableCopy];
[mutableCopyArray enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
[mutableCopyArray replaceObjectAtIndex:idx withObject:[object modifiedObject]];
}];
Checkout How do I iterate over an NSArray?
While this may work to some degree, I haven't tested it, I'd file this under 'bad idea' and not touch. NSArray, and many other cocoa objects, a fairly complex and can have a variety of implementations under the hood as part of the class cluster design pattern.
So when it comes down to it you really won't know what you're dealing internally. NSArray is actually designed to be immutable so in place editing is even doubly a bad idea.
Objects that are designed to let you mess around with the internals expose those through api methods like NSMutableData's mutableBytes.
You're better off constructing a new NS(Mutable)Array with the processed values.