Array from different classes - objective-c

i have a class Devices and several subclasses like mobiles, watches etc.
I just wondering is it possible to create an array from all of these subclasses? I have to create objects from class1 class2 etc and put them to an array. This array must contain objects from different classes. The array must have 200 elements. And can you please give an example.
Thanks in advance

Yup, it's perfectly possible:
NSArray *array = #[
#"a string",
#1337, // a NSNumber
[UIImage imageNamed:#"anImage"],
//... and so on
]

So i think i didn't post the question proper. I have to create objects from class1 class2 etc and put them to an array. This array must contain objects from different classes

I guess you are looking for something like this:
NSMutableArray *yourArray = [[NSMutableArray alloc] init];
ObjectType1 *object1 = [[ObjectType1 alloc] init];
[yourArray addObject: object1];
ObjectType2 *object2 = [[ObjectType2 alloc] init];
[yourArray addObject: object2];
ObjectType3 *object3 = [[ObjectType3 alloc] init];
[yourArray addObject: object3];
This way you'll have an array with 3 items. This are 3 objects each with a different object type. Note that you have a good administration for the reading of the objects.
The following is wrong, because you are reading the first object which is of type ObjectType1, and you are assigning it to ObjectType2.
ObjectType2 *readingObject = [yourArray objectAtIndex:1]; // WRONG!

Related

Confusion about modifying NSMutableArray contents after using addObject:

So, when I modify things inside of an NSMutableArray I don't get the result I expect. I think the best way to frame this question is with an example. The following code prints "george" (as expected):
NSMutableArray *originalArray = [[NSMutableArray alloc] initWithObjects:#"sally",#"george", nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
[secondArray addObject:originalArray[1]];
secondArray[0] = #"priscilla";
NSLog(#"%#",originalArray[1]);
But this code prints "priscilla":
TestClass *test1 = [[TestClass alloc] init];
test1.clientName = #"sally";
TestClass *test2 = [[TestClass alloc] init];
test2.clientName = #"george";
NSMutableArray *originalArray = [[NSMutableArray alloc] initWithObjects:test1,test2, nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
[secondArray addObject:originalArray[1]];
TestClass *objectTakenFromSecondArray = secondArray[0];
objectTakenFromSecondArray.clientName = #"priscilla";
NSLog(#"%#", ((TestClass *)originalArray[1]).clientName);
I thought that addObject: always copied the object before adding it to the array receiving the addObject: message. Is this not the case?
Thanks!
p.s. here is the interface and implementation for TestClass in case it is pertinent:
#interface TestClass : NSObject
#property (strong,nonatomic) NSString *clientName;
#end
#implementation TestClass
#synthesize clientName = _clientName
#end
I thought that addObject: always copied the object before adding it to the array receiving the addObject: message. Is this not the case?
addObject: does not copy the object. NSArray does not require that its contents even be copyable (not everything is). That probably explains the confusion. If you want to copy it, you need to do so yourself.
You pretty much answered your own question. When you create an NSMutableArray and add an object to it, you are just creating a pointer to that object, wherever it is stored. If you add the same object to another NSMutableArray, that too contains a pointer to the same thing. You might not need the analogy, but for anyone else confused - the NSMutableArray is like a postman with an address to post to, and the object is the house at that address. Two postmen (or two arrays) can have an address for the same house, but there is only one house still. (That is, unless someone explicitly 'copies' the house).
So in your second to last line of code, where you change that .clientName property, you are changing the property of the original *test2 object.
Worth noting in this case, that if you remove that second array, you don't remove the objects it contains necessarily. So in your case, removing that second NSMutableArray from memory does not mean that all of its objects also disappear from memory - unless everything else that points to those objects also is removed. The array does not contain pointers to unique copy of those objects - it just points to the originals.

How to copy NSArray to another NSArray?

I have many different NSArrays, and according to the users choice I want one of them to be copied to a new NSArray. How do I copy one NSArray to another?
There can be several ways for this-
array1 = [array2 copy];
Use initWithArray method.
You can also use initWithArray:copyItems: method. (This if for NSMutableArray)
you can use the
NSArray *_newArray = [NSArray arrayWithArray:_oldArray];
or if you prefer better, you can use:
NSArray *_newArray = [[NSArray alloc] initWithArray:_oldArray];
(in that case the object of the first array won't be copied, that get only a retain front he second NSArray, you can remove the object from any array it won't affect the other array, but if you change any object in any NSArray it will be changed in the other one as well because there is both of the old and the new array is working with the same instance of the objects.)
if your plan is to make another instance of the old objects in the new array:
NSArray *_newArray = [[NSArray alloc] initWithArray:_oldArray copyItems:true];
if you are using the ARC, you won't need to do anything else, if you are not, in the case of both -initWithArray: or -initWithArray:copyItems: you should use the [_newArray release]; to release the array after you don't want to use anymore.
As well as
NSArray *newArray = [oldArray copy];
if you need to add/remove from the new array, the simplest way to make a mutable copy is:
NSMutableArray *editableArray = [oldArray mutableCopy];
The above functions both make shallow copies, for deep copy it's as #holex and #rishi mentioned
NSArray *newArray = [[NSArray alloc] initWithArray:oldArray copyItems:true];
NSMutableArray *editableArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:true];

NSCFArray not acting as NSArray

I'm trying to save data to and XML file on Iphone. For that, I load the wholeXML, add new data and the save it again. The problem arises when i try to store the new data, my
[mArray addObject:newData];
methods crashes, as mArray is not a NSMutableArray, instead, it is a NSCFArray even if I applied a mutableCopy method to it.
As I understand, a NSCFArray is a toll-free bridging to an NSArray, so I can't understand why the mutablyCopy method is not working.
Any idea??
NSMutableDictionary *wholeXML = [[NSMutableDictionary alloc] init];
wholeXML = xmlData;
NSArray *array = [[NSArray alloc] init];
NSMutableArray *mArray = [[NSMutableArray alloc] init];
array = [wholeXML objectForKey:#"Key"];
mArray = [a mutableCopy];
NSCFArray is a private subclass that gets instantiated when you do things with NSArray factory methods or initializers. You're doing too many initializations. Try this simplified version:
NSMutableDictionary *wholeXML = [[NSMutableDictionary alloc] initWithDictionary:xmlData];
NSMutableArray *mArray = [[NSMutableArray alloc] initWithArray:[wholeXML valueForKey:#"Key"]];
NSCFArray is the concrete class for both NSMutableArray and NSArray. It sounds like you are simply mistaken about what kind of array you have. Since the code you posted is obviously not your real code (it won't even compile, and wouldn't exhibit the problem even if it did), it's impossible to tell at what point your program is assigning an immutable array to the variable. But that's what it sounds like is happening.
I will say (and please don't take this as a personal criticism — it's just an observation) that the code you posted suggests you don't have a strong grasp on how classes and object identity work. That's probably the root cause here.
All three of your variables you initialize with [[Something alloc] init], but then you immediately throw away the object and replace it with something else. This means the original object (NSMutableArray in this case) just gets leaked and the variable now contains the new object you have assigned. If that new object isn't an NSMutableArray, it won't magically be turned into one just because that's what the variable held before.

Objective-C identifier from NSString

I want to pass an NSString to a method and have that particular NSString name a new NSSMutableArray. Confusing? Programmatically looks like this:
+ (void)newMutableArrayWithName:(NSString*)theArrayName
{
NSLog(#"Creating an array that is named: %#",theArrayName);
NSMutableArray* theArrayName = [[NSMutableArray alloc] init];
}
Unfortunately, "theArrayName" is not affiliated with the argument passed to the method. Is there any way this is achievable?
The name of a variable is used by the compiler, and is set at compile-time, not at run time.
If you need to be able to associate a label with an array, I suggest that you use an NSDictionary to do something like this
NSString *theArrayName = #"My Cool Array";
NSMutableArray *theArray = [NSMutableArray array];
NSDictionary *theDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
theArray, theArrayName, nil];
You could have multiple "named" arrays in the dictionary, if you wanted, and could access them by the names that you gave them
[theDictionary objectForKey:#"My Cool Array"];
Look into key-value coding for setting the values of existing properties by the property's name, but it appears it can't create a new property. For that, you should just use a dictionary.

Terminology question regarding looping thru an NSArray in Objective-C

When you have an NSArray and you want to evaluate and change the elements, you can't change the array from inside the loop. So, you create a mutable copy that can be changed.
code example:
NSMutableArray *bin = [NSMutableArray arrayWithObjects:#"0", #"1", #"2", #"3", #"4", #"5", #"6", #"7", nil];
NSMutableArray *list = [NSMutableArray arrayWithObjects:#"a1", #"b2", #"c3", #"e4", nil];
NSMutableArray *listHolder = list; // can't mutate 'list' within loop so create a holder
for (int i = 0; i < [list count]; i++) {
[listHolder replaceObjectAtIndex:i withObject:[bin objectAtIndex:i]];
}
What is that second array listHolder called? I mean, what term is used to refer to an array in this context.
This is perfectly valid:
NSMutableArray *bin = [NSMutableArray arrayWithObjects:#"0", #"1", …, #"7", nil];
NSMutableArray *list = [NSMutableArray arrayWithObjects:#"a1", …, #"e4", nil];
// NSInteger should be used instead of int
for (NSInteger i = 0; i < [list count]; i++) {
[list replaceObjectAtIndex:i withObject:[bin objectAtIndex:i]];
}
You're not allowed to change the array inside a for … in or NSEnumerate loop, but using an index is perfectly valid.
What troubles me is your misunderstanding of pointers.
If it were a loop in which you weren't allowed to mutate the array this wouldn't copy the array but only the pointer to the array, effectively modifying the array you're not allowed to. (I'm not even sure if this works.)
Instead of just copying the pointer
// can't mutate 'list' within loop so create a holder
NSMutableArray *listHolder = list;
make a true copy:
NSMutableArray *copy = [[list mutableCopy] autorelease];
In case I really have to make a copy I try to name it according to its content. For example:
NSMutableArray *views;
NSMutableArray *reorderedViews = [views mutableCopy];
// reorder reorderedViews
Sometimes it's hard to find a good enough name, then I usually just use nameCopy.
In this context listHolder would be called a copy.
Your code has a bug though. This line is not actually making a copy, it is only letting listHolder and list both reference the same array object:
NSMutableArray *listHolder = list;
This would be an actual copy:
NSMutableArray *listHolder = [list mutableCopy];
Make sure that you use mutableCopy and not just copy if you want the copy to be mutable. The copy method will return immutable variants on all mutable classes such as NSMutableSet, NSMutableDictionary, and so forth.
Also as others have noted it is only inside the for (item in collection) loop that the enumerated collection can not be mutated. In a normal for (;;) mutation is perfectly ok, but can lead to strange result if the number of items in the collection changes.
There is not specific stylistic or common name for this that is universally used, it is your code afterall, and if there appropriate terms for them use them.
Having said that generally if you don't have specific names in this sort of situation then people refer to the original list as the "source" (src) and the final list as "destination" (dst), just like in a memory blitting style operation.
A temporary mutable copy of the original NSArray would be how I would refer to it.