NSArray copy for undo /redo purposes - objective-c

If I have an nsarray full of custom objects and I make a second array using:
NSArray *temp = [NSArray arrayWithArray:original];
then work with some properties of the objects inside the original array, then decide to roll back, I am then using the reverse:
original = [NSArray arrayWithArray:temp];
I am finding the objects I changed in the array also effected my temp array. I also tried implementing copyWithZone on my custom class, and using copyItems and it did not help. What else should I try?
To be clear, in order to use copyWithZone, I changed my array creation command to:
NSArray *temp = [[NSArray alloc] initWithArray:original copyItems:YES];
My copyWithZone:
-(id)copyWithZone:(NSZone *)zone{
CustomObject *ret = [[CustomObject allocWithZone: zone] init];
//copy properties
return ret;
}

Related

Remove object from NSMutableArray after parsing JSON

The JSON source formatted with jsonviewer.stack.hu:
My Parse Method (simplified):
- (void)parseMethod {
// OTHER STUFF
arrayList = [[NSMutableArray alloc] init];
NSURL *url2 = // THE URL SOURCE OF JSON OBJECT, ON A REMOTE SERVER
NSURLRequest *request2 = [NSURLRequest requestWithURL:url2 cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:5.0];
AFJSONRequestOperation *operation2 = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request2
success:^(NSURLRequest *request2, NSHTTPURLResponse *response2, id JSON)
{
arrayList = [JSON objectForKey:#"list"];
// HERE I TRIED TO WRITE [arrayListPrev removeObjectAtIndex:0];
NSMutableArray *arrayList1 = [arrayList valueForKey:#"list1"];
}
failure:^(NSURLRequest *request2, NSHTTPURLResponse *response2, NSError *error2, id JSON2) {
}];
[operation2 start];
}
The problem:
After the parsing I want to remove the FIRST OBJECT of array named "list", because I must populate the rows of a UITableView with all the values of list1 in the arrays EXCEPT the first ( list array->array number 0->list1 value of 0 ). I have tried the code:
[arrayList removeObjectAtIndex:0];
In several position but app crashes with error:'-[__NSCFArray removeObjectAtIndex:]: mutating method sent to immutable object'... so what's the best way to REMOVE the FIRST object (array number 0) from that NSMutableArray *list AFTER the parsing, to ELIMINATE The list1 value of 0 object? Thanks!
In spite of you write arrayList = [[NSMutableArray alloc] init];
Here, as i guess, you assign simple immutable array instance
arrayList = [JSON objectForKey:#"list"];
You can do this instead:
arrayList = [[JSON objectForKey:#"list"] mutableCopy];
[arrayList removeObjectAtIndex:0];
The problem is that you are working with an NSArray and not an NSMutableArray. This is probably due to the fact your parser returns immutable objects. What you need to do is take that NSArray, create an NSMutableArray with it and then remove the first object
NSMutableArray *_arrayList = [NSMutableArray arrayWithArray:arrayList];
[_arrayList removeObjectAtIndex:0];
// dont forget to store your array wherever you need it
The Error shows that your array is having value of immutable type.Use a mutable copy or initialize your arrayList with -arrayWithArray: method.Hope it fixes the problem.
Note: allocate NSMutableArray to initialize with initWithCapacity method
As other's have suggested, you're working with an NSArray, which is not Mutable (Editable). I'm going to add my input though with a new function:
NSMutableArray *mutableArrayList = [arrayList mutableCopy];
This creates a mutable copy of the array.

Objective C: Releasing a list, will it cause potential leaks?

Tried finding the answer online, but couldn't. So i'm wondering if anyone else knows and why?
Say I have an NSDictionary, or NSArray, that stores objects inside of them. If I release the NSDictionary, is there a potential leak because I didn't release the objects inside of the NSDictionary list?
For example:
NSDictionary *dict = [NSDictionary alloc] init];
// Create a bunch of objects, NSStrings, etc.
// Store it into dict.
[dict release];
Will that also release everything inside of the dict? (objects, nsstrings, etc).
Thanks in advance people!
All items in an NSDictionary or NSArray are automatically retained when they're added and released when removed, or when the list is destroyed.
For example:
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
MyObject *obj = [[MyObject alloc] init];
[dict setObject:obj forKey:#"foo"]; // the dictionary retains "obj"
[obj release]; // this matches the "alloc/init"
// but "obj" still is retained by the dictionary
[dict release]; // now "obj" gets released
When you do a release on a NSDictionary or NSArray, as long as the retain count of the objects inside the array is 1 (meaning as long as you released the objects after you inserted them inside the data structure), then once you release the dictionary or array, those objects will be released as well.

Change from a NSMutableArray to a .plist

I have been working through several tutorials on uitableviews.
I have put, as instructed, all the info into a 'listofitems' as below
listOfItems = [[NSMutableArray alloc] init];
NSArray *countriesToLiveInArray = [NSArray arrayWithObjects:#"Iceland", #"Greenland", #"Switzerland", #"Norway", #"New Zealand", #"Greece", #"Rome", #"Ireland", nil];
NSDictionary *countriesToLiveInDict = [NSDictionary dictionaryWithObject:countriesToLiveInArray forKey:#"Countries"];
NSArray *countriesLivedInArray = [NSArray arrayWithObjects:#"India", #"U.S.A", nil];
NSDictionary *countriesLivedInDict = [NSDictionary dictionaryWithObject:countriesLivedInArray forKey:#"Countries"];
[listOfItems addObject:countriesToLiveInDict];
[listOfItems addObject:countriesLivedInDict];
This creates a sectioned table view. I would like to know how to change it into a .plist instead of typing it all out into the RootViewController.m. I would still like it to be in a sectioned tableview.
Is there a simple method for changing from this NSMutableArray,NSArray and NSDictionary to a plist?
There's a simple method for this writeToFile:atomically::
[listOfItems writeToFile:destinationPath atomically:YES];
This will automatically create a file with plist inside it.
that sorta depends on what you want in a plist, and what you put into it. if the entries and contents are all CFPropertyList types (CFString,CFDate,CFData,CFDictionary,CFArray,CFNumber...) then just create it with something like CFPropertyListCreateDeepCopy.
if you have non-convertible custom objects (e.g., your own NSObject subclasses), then see the cocoa archiving topics.
This is the simple function end hear relization
This is function is updating NSArray
- (void) WriteRecordToFile:(NSMutableDictionary*)countDict {
// Here to write to file
databasePathCallCount = #"plist path";
NSMutableArray *countArray = [NSMutableArray arrayWithContentsOfFile:databasePathCallCount];
if(countArray)
[countArray addObject:countDict];
[countArray writeToFile:databasePathCallCount atomically:NO];
}

Objective-c NSMutableArray release behaviour

Does the release, recursively releases all inner objects? or must it be done manualy?
Can I do just this?
NSMutableArray *list = [[NSArray alloc] init];
// ...
// fill list with elements
//...
[list release];
Or must I release all inner objects one by one before releasing the NSMutableArray? // Suposing there isn't any other reference to the contained objects, except on the list itself.
Yes it does. It retains them when added, and releases them when dealloc'd. This is actually one of the most common questions I see here.
If you are owning the object then you will have to release it.
NSMutableArray *list = [[NSArray alloc] init];
NSString *str = [[NSString alloc] init] // you are the owner of this object
[list addObject:str];
[str release]; // release the object after using it
[list release];
If you are not the owner of the object then you should not release.
NSMutableArray *list = [[NSArray alloc] init];
NSString *str = [NSString string]; // you are not owning this object
[list addObject:str]; // str retain count is incremented
[list release]; // str retain count is decremented.
This is the concept which even array also uses. When you add any object to the array, array will retain it. In the sense it becomes the owner of that object and It will release that object when you release the array.

Initializing an instance variable

With an instance variable myArray:
#interface AppController : NSObject
{
NSArray *myArray;
}
Sometimes I see myArray initialized like this:
- (void)init
{
[super init];
self.myArray = [[NSArray alloc] init];
return self;
}
and sometimes I see it with a more complicated method:
- (void)init
{
[super init];
NSArray *myTempArray = [[NSArray alloc] init];
self.myArray = myTempArray
[myTempArray release];
return self;
}
I know that there's no difference in the end result, but why do people bother to do the longer version?
My feeling is that the longer version is better if the instance variable is set up with a #property and #synthesize (possibly because the variable has already been alloced). Is this part of the reason?
Thanks.
If myArray is a property and it's set to retain or copy (as it should be for a property like this), then you'll end up double-retaining the variable when you do this:
self.myArray = [[NSArray alloc] init];
The alloc call sets the reference count to 1, and the property assignment will retain or copy it. (For an immutable object, a copy is most often just a call to retain; there's no need to copy an object that can't change its value) So after the assignment, the object has retain count 2, even though you're only holding one reference to it. This will leak memory.
I would expect to see either a direct assignment to the instance variable
myArray = [[NSArray alloc] init];
Or proper handling of the retain count:
NSArray *newArray = [[NSArray alloc] init];
self.myArray = newArray;
[newArray release];
Or the use of autoreleased objects:
self.myArray = [[[NSArray alloc] init] autorelease]; // Will be released once later
self.myArray = [NSArray array]; // Convenience constructors return autoreleased objects
This is an idiom used in mutators (sometimes called "setters"), but I think you typed it slightly wrong. Usually it looks like this:
-(void)setMyName:(NSString *)newName
{
[newName retain];
[myName release];
myName = newName;
}
The new name is retained, since this instance will need to keep it around; the old name is released; and finally the instance variable is assigned to point to the new name.
I have a feeling you mean this:
NSArray* a = [NSArray arrayWithObjects:#"foo", #"bar", nil];
and this
NSArray* a = [[NSArray alloc] initWithObjects:#"foo", #"bar", nil];
//...
[a release];
With the first style, the static method performs an alloc/init/autorelease on it for you so you don't have to. With the second style, you have more control over when the memory is released instead of automatically releasing when you exit the current block.
That code will crash your application. The second version only copies the pointer then releases the instance. You need to call [object retain] before releasing the reference.