NSArray create with some elements plus another NSArray - objective-c

I am trying to use model inheritance on realm. So I minded up using the code below to override and also call super method.
+ (NSArray *)requiredProperties {
return #[[super requiredProperties], #"thisIsRequired",#"thisIsAlsoRequired"];
}
So the question: is it OK to create an NSArray on the fly while also using another NSArray and some more elements:
NSArray *mySecondArray = #[myFirstArray, #"andSomeExtras", #"alsoMoreExtras"];
What I have been expecting is; first element of mySecondArray should be the first element of myFirstArray. Second element of mySecondArray should be the second element of myFirstArray and so on. (size of myFirstArray) +1 th element of mySecondArray should be #"thisIsRequired" .
Or I am making up some kind of magix?
Well, as you can see I am new to the stuff and I might be confused.

In general, it is okay to instantiate such heterogeneous arrays with Foundation. It's just not what you want here. In your example, you would end up with the following instead:
NSArray *myFirstArray = #[#"firstsFirstsElement", #"firstsSecondElement"];
NSArray *mySecondArray = #[myFirstArray, #"andSomeExtras", #"alsoMoreExtras"];
/* =>
#[
#[#"firstsFirstsElement", #"firstsSecondElement"],
#"andSomeExtras",
#"alsoMoreExtras",
]
*/
You're looking for - arrayByAddingObjectsFromArray:. You can use it like seen below:
+ (NSArray *)requiredProperties {
return [super.requiredProperties arrayByAddingObjectsFromArray:#[
#"thisIsRequired",
#"thisIsAlsoRequired",
]];
}

Yes it is Ok, as long as you will remember what you are doing anywhere in your code.
However you usually reserve the use of NSArray for a homogeneous collection of objects and use NSDictionary, or better your own DTO class, for heterogeneous aggregation of data.
NSArray official documentation show a similar example in the section dedicated to the method arrayWithObjects:
NSArray is really an array of id, even with generics enabled.
This other link about Objective C generics may also help understand the nature of the raw NSArray class.

Why not use NSMutableArray and just add the objects?
NSMutableArray *mySecondArray = [myFirstArray mutableCopy];
[mySecondArray addObject:#"andSomeExtras"];
[mySecondArray addObject:#"alsoMoreExtras"];

Related

How to check assignment since addObject doesn't access setter?

I just noticed that calling addObject: on an NSMutableArray doesn't access that array's setter.
E.g., for NSMutableArray self.myArray, [self.myArray addObject:object] does not use [self setMyArray:array] to add the object.
Previously I have been using custom setters and getter to check assignment before assigning; e.g., if I wanted an array that only accepted objects of class MyClass, I would do the following:
- (void)setMyArray:(NSMutableArray *)myArray
{
for (id object in myArray)
{
if (![object isKindOfClass:[MyClass class]]) return;
}
_myArray = myArray;
}
- (NSMutableArray *)myArray
{
if (!_myArray) _myArray = [[NSMutableArray alloc] init];
_myArray = myArray;
}
How do I go about achieving this same functionality when changing the array via addObject:, removeObject:, and other similar functions that may circumvent the setter?
Generally this kind of problem is the reason why NSMutableArray is usually avoided in preference of NSArray.
This is the simple solution, use NSArray instead of NSMutableArray:
self.myArray = [self.myArray arrayByAddingObject:foo];
However, if the array is really big that will cause performance issues. Then you've got two options:
you can have your own addObjectToMyArray: method in your class and always use that
you can create an NSArrayController and use that to access your array. It will implement key value observing and bindings and all of that stuff.
NSMutableArray is designed to perform addObject: with as few CPU instructions as possible and therefore does not proved any way for external code to be notified that the object was added. You have to have some other class wrapped around it.
Do not try to subclass NSMutableArray, because it is a "class cluster" making subclasses extremely complicated.
If what you wish to do is ensure objects in the array are of a particular class then this answer to the question "NSMutableArray - force the array to hold specific object type only" provides code to do exactly that.
If you wish to do other checks on assignment then you can use the code in that answer as a starting point.

Quick way to tell what objects NSArray contains

I'm currently working with someone else code, so i have a question is there a way to quickly tell what objects i have in NSArray.
In code i have for example:
Someclassobj.arr
And i know there is an array as a property in Someclassobj and of course i can see the definition of it, but still dont know what objects are inside. Could be NSString, NSDictionary,ObjectDefinedByUSer... How to quicly tell?
There is a method to check classes? If i execute:
id someUnknownObj = [Someclassobj.arr objectAtIndex:0];
How to check it? (i know isKindOfClass isMemberOfClass methods, but its doesn't work for me).
Of course there is doesn't have to be code method, could be something like option+click.
Will do the trick:
NSLog(#"%#",yourArray);
If you want to avoid this kind of stuff:
1) Put a breakpoint as soon as the NSArray has the objects.
2) Go to the Console on Xcode and do:
po yourArray
A great article about using the console in Xcode here.
you can do stk like this :
NSArray *arr; // Array with random stuff
for (id elt in arr) {
if ([elf iskindOfClass:[NSString class]])
NSLog(#"Object = NSString);"
}

Objective-c Workaround for running intepretted code

I'm used to using eval() in languages like javascript e.t.c.
In cocos2d, to select the level, I am passing "1" or "2" to my Loadlevel.m file, the level Classes are named "LevelOne" and "LevelTwo" accordingly, I wanted to create a dictionary lookup that paried "1" => "LevelOne" e.t.c then run eval on that string to effectively call [MyLevel node];
Apparently we can't use eval in IOS code, so how would I go about doing this?
Try using the NSStringFromClass and NSClassFromString functions.
Specifically, represent the classes as strings in your dictionary, e.g.,
[myDictionary setObject:NSStringFromClass([LevelOne class]) forKey:#"1"]
Then, to use the right level from your dictionary, you could do:
NSString *levelAsString = [myDictionary objectForKey:#"1"];
id node = [NSClassFromString(levelAsString) node]
(I'm assuming +node is a class method)
Now, this is a pretty uncommon and odd design in Cocoa. Perhaps if you explain more about what you're doing, we could suggest alternate design choices that might be better.
I'm not one hundred percent clear on what you're asking, but you can store class objects directly in your dictionary, retrieve them, and send them messages:
NSDictionary * d = [NSDictionary dictionaryWithObjectsAndKeys:[LevelOne class], #"1", [LevelTwo class], #"2", nil];
Class selectedLevel = [d objectForKey:#"1"];
[selectedLevel node];

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;
}

Question regarding programming structure of a recursive method

I have this method and it's kind of really big so I can't include it in this post. It takes an array as parameter and tests its objects (NSStrings). Sometimes -but not always-, the method calls itself with an array containing one of those strings. If every test is passed, then the NSString is sent to another method which processes it. This all works fine but now I'm working on a different approach. I want to call the method and let it return an array of all NSStrings that passed the test successfully. But since the method calls itself I don't really know how to do this. Instead of processing it, I could add all successfully tested NSStrings to an array but that array would then needed to be accessible in all methods. What is recommended here? I would like to avoid public variables..
- (void)doStuff: (NSArray *)array { //A quick (very short) example of what I have now.
for (NSString *string in array) {
if ([string isEqualToString: #"test"])
[self doStuff: [NSArray arrayWithObject: #"test2"]];
else
[self processStuff: string];
}
}
You can add a mutable array as one of its parameters and add the result there:
- (void)doRecursiveWithData:(NSArray *)array storeResultsIn:(NSMutableArray *)results {
if ( shoudGoDeeper )
[self doRecursiveWithData:(your new array)];
else
[results addObject:(whatever you want to store)]; // or use another method to so so
}
I know your example is just that, an example, but maybe it's worth thinking about how you can go without the recursion - in many ways that's easily doable and often performs better.