i have one array this array contain Question Objects so here i need to change the positions for array
Question *que=[[Question alloc]init];
que=[myarray objectAtIndex:1];
Question *que1=[[Question alloc]init];
que1=[myarray objectAtIndex:2];
here i need to inter change objects each other some
[que1 setValue: que.name forKey:#"Name"];
[myarray relplaceObjectAtIndex:2 withObject:que1];
is it right way to set value same objectValues
Please guide me hoe can inter change value.
Thanks for advance
There are significant issues with your code here:
This statement:
Question *que = [[Question alloc] init];
Allocates a new Question instance and assigns it to the variable que. When you do:
que = [myarray objectAtIndex:1];
You are overwriting the Question instance that you just allocated, effectively leaking memory (because you never released it). This won't be a problem if you are using ARC but nevertheless it is something to be mindful of because with or without ARC it is pointless. You did this twice, once for que and once for que1. Since you don't actually need to allocate and initialise a new Question instance, you can just do:
Question *que = [myarray objectAtIndex:1];
You obtain a reference to a Question object and assign it to que1. Then you mutate it and want to put it back into the array. This is pointless because the array already holds a reference to the same Question instance that you obtained with objectAtIndex:.
You haven't really explained what you are trying to do. Your entire code basically boils down to:
[[[myarray objectAtIndex:2] setValue:[[myarray objectAtIndex:1] name] forKey:#"Name"];
Your code should work how you intend with what you have shown. Just a few points to be aware of:
You need myarray to be an NSMutableArray
You have a typo here: relplaceObjectAtIndex:2 it should be replaceObjectAtIndex
Arrays start at index 0, which I'm sure you are aware of.
First use NSMutableArray object to hold it not NSArray
then.
you need to understand one main thing you are holding only a pointer to an object. array is managing it. You have created an object before accessing object inside array, dont do that it creates memory leak. You have to access the object from array only.
Question * que1=[myarray objectAtIndex:1];
[que1 retain];
[myarray removeObjectAtIndex:1];
Question * que2=[myarray objectAtIndex:2];
[que2 retain];
[myarray removeObjectAtIndex:2];
its possible you are not using ARC and your array is the only owner of the object. So If you remove object from array the it might release the whole object
[myarray insertObject:que2 atIndex:1];
[myarray insertObject:que1 atIndex:2];
this is a sample to put object in any position.
Read class references NSMutableArray
Related
I'm new to cocoa / objective-c and i'm struggeling with the releases of my objects. I have the following code:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
}
The analyzer shows me that the "gastrocategory" defined in the for is a potential memory leak. But i'm not sure if i can release this at the end of the for loop?
Also at the following code:
- (NSArray *)eventsForStage:(int)stageId {
NSMutableArray *result = [[NSMutableArray alloc] init];
for (Event *e in eventList) {
if ([e stageId] == stageId) {
[result addObject:e];
}
}
return result;
}
The Analyzer tells me that my "result" is a potential leak. But where should I release this?
Is there also a simple rule to memorize when i should use assign, copy, retain etc. at the #property ?
Another problem:
- (IBAction)showHungryView:(id)sender {
GastroCategoriesView *gastroCategoriesView = [[GastroCategoriesView alloc] initWithNibName:#"GastroCategoriesView" bundle:nil];
[gastroCategoriesView setDataManager:dataManager];
UIView *currentView = [self view];
UIView *window = [currentView superview];
UIView *gastroView = [gastroCategoriesView view];
[window addSubview:gastroView];
CGRect pageFrame = currentView.frame;
CGFloat pageWidth = pageFrame.size.width;
gastroView.frame = CGRectOffset(pageFrame,pageWidth,0);
[UIView beginAnimations:nil context:NULL];
currentView.frame = CGRectOffset(pageFrame,-pageWidth,0);
gastroView.frame = pageFrame;
[UIView commitAnimations];
//[gastroCategoriesView release];
}
I don't get it, the "gastroCategoriesView" is a potential leak. I tried to release it at the end or with autorelease but neither works fine. Everytime I call the method my app is terminating. Thank you very much again!
In your loop, release each gc after adding it to the list since you won't need it in your loop scope anymore:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
[gc release];
}
In your method, declare result to be autoreleased to absolve ownership of it from your method:
NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
// An alternative to the above, produces an empty autoreleased array
NSMutableArray *result = [NSMutableArray array];
EDIT: in your third issue, you can't release your view controller because its view is being used by the window. Setting it to autorelease also causes the same fate, only delayed.
You'll have to retain your GastroCategoriesView controller somewhere, e.g. in an instance variable of your app delegate.
BoltClock's answer is spot-on as to the first part of your question. I'll try to tackle the rest.
Assign is for simple, non-object types such as int, double, or struct. It generates a setter that does a plain old assignment, as in "foo = newFoo". Copy & retain will, as their names imply, either make a copy of the new value ("foo = [newFoo copy]") or retain it ("foo = [newFoo retain]"). In both cases, the setter will release the old value as appropriate.
So the question is, when to copy and when to retain. The answer is... it depends. How does your class use the new value? Will your class break if some other code modifies the incoming object? Say, for example, you have an NSString* property imaginatively named "theString." Other code can assign an NSMutableString instance to theString - that's legal, because it's an NSString subclass. But that other code might also keep its own reference to the mutable string object, and change its value - is your code prepared to deal with that possibility? If not, it should make its own copy, which the other code can't change.
On the other hand, if your own code makes no assumptions about whether theString might have been changed, and works just as well whether or not it was, then you'd save memory by retaining the incoming object instead of unnecessarily making a copy of it.
Basically, the rule, which is unfortunately not so simple sometimes, is to think carefully about whether your own code needs its own private copy, or can correctly deal with a shared object whose value might be changed by other code.
The reason you can release gc after it is added to the gastroCategoryList is that when an object is added to an array, the array retains that object. So, even though you release your gc, it will still be around; retained by the gastroCategoryList.
When you are returning a newly created object from a method, you need to call autorelease. This will cause the object to be released only after the runtime leaves the scope of the calling method, thereby giving the calling method a chance to do something with the returned value.
Note that if your method starts with the word copy or new, then you should not autorelease your object; you should leave it for the calling method to release.
As for copy vs retain vs assign... as a general rule, copy objects that have a mutable version, such as NSArray, NSSet, NSDictionary, and NSString. This will ensure that the object you have a pointer to is not mutable when you don't want it to be.
Otherwise, use retain whenever you want your class to be ensured that an object is still in memory. This will apply to almost every object except for objects that are considered parents of your object, in which case you would use assign. (See the section on retain cycles here).
Also note that you have to use assign for non-object types such as int.
Read through the Memory Management Programming Guide a bit; it's quite helpful.
The data source for my table view is a plain NSMutableArray that will be populated as the app runs, but will be empty when the Table View first loads. The class interface looks like this...
#interface ViewController_iPhone : UITableViewController {
NSMutableArray *serverList;
}
#property (retain, readonly) NSMutableArray *serverList;
#end
My questions are...
Currently, I initialize it in the viewDidLoad method like so...
serverList = [[NSMutableArray alloc] initWithCapacity:1];
I do it this way because the array needs to be valid in order for my numberOfRowsInSection method to avoid crashing when reading the count of the array (which will be zero) when the view first loads. My current approach of using initWithCapacity just feels a little clunky since I just need an empty, but valid array object that will return a count value of zero when the view loads. How should I be initializing my serverList array?
While playing around, I noticed that when I try and initialize the serverList array this way...
serverList = [NSMutableArray arrayWithCapacity:1];
it crashes on that line. Why?
Thanks in advance for all your help!
Here's a key concept to learn about member variables and properties: Member variables are not the same as properties.
That is, when accessing a member variable in your class:
serverList = [NSArray array]; is not the same as self.serverList = [NSArray array];
serverList by itself means you're accessing it directly.
self.serverList means you're using the getter/setter methods to access it.
Normally this isn't that big of a deal when dealing with basic variable types. However, when your property uses retain or copy, that means your setter method will automatically retain it when you use it, but it won't do such when you access it directly.
That means:
serverList = [NSArray array]; will not retain the array.
self.serverList = [NSArray array]; will retain the array.
It should be noted that [NSMutableArray arrayWithCapacity:1]; (and 99% of other methods that aren't alloc) will return an object that is autoreleased. If you want to keep it for later use, as you need to in this case, then you must retain it in some form or fashion.
I somehow missed the simplest approach and found that when I simply create the array like so...
serverList = [[NSMutableArray alloc] init];
and release it in the dealloc method, everything works great!
Note that capacity does not mean any objects are in the array. Using -initWithCapacity: simply sets aside a chunk of space for the array. Nothing is in the array even with a non-zero capacity.
The following initializers:
self.serverList = [[[NSMutableArray alloc] init] autorelease];
self.serverList = [[[NSMutableArray alloc] initWithCapacity:capacity] autorelease];
self.serverList = [NSMutableArray array];
self.serverList = [NSMutableArray arrayWithCapacity:capacity];
should all work, however.
Make sure you specify self so that the property is accessed. Using serverList by itself will not work.
Make sure you autorelease any alloc-init of a property which you are retaining, otherwise you will have a memory leak.
You do not need an array with a specified capacity. This is just a performance convenience for setting aside contiguous memory, and useful if you have a rough idea how much space your array will need up-front. An array that is created through alloc-init will also be empty, with a count of zero.
I am trying to append objects to my data source and then reload the table. Is this the correct way of approaching it?
self.items is my datasource
//Copy current items
self.itemsCopy = [self.items mutableCopy];//[[NSMutableArray alloc] initWithArray:self.items copyItems:NO];
NSLog(#"Copy Size before append: %d",[itemsCopy count]);
//Get new items
int lastMsgID = [self getLastMessageID];
[self.coreData getMoreMessages:self.title lastID:lastMsgID]; //This will update self.items with 30 objects
//Append new items
[itemsCopy addObjectsFromArray:self.items];
//Empty items and copy itemsCopy
[self.items removeAllObjects];
self.items = [self.itemsCopy mutableCopy];
NSLog(#"Actual Size after append: %d",[self.items count]);
//Reload data
[tableView reloadData];
try
[tableView reloadData];
in the viewWillAppear method....
Yes, looks about right to me.
Depending on how your properties are declared, you may have some memory issues here.
If your properties specify retain as an attribute, then setting assigning a copy of an array to them will result in a retain count of 2 on the object rather than the intended 1.
Eg.
self.myProperty = [myArray mutableCopy];
mutableCopy returns a newly allocated object with a retain count of one. The caller owns this object and is responsible for releasing it. Then you assign it to your property which retains it, increasing the retain count to 2. The object will be leaked when the owner is deallocated because the property will only be released once.
The solution would be to release the mutable copy after assigning and retaining it to to the property like this.
self.myProperty = [myArray mutableCopy];
[self.myProperty release];
Alternatively you could auto release the result of mutableCopy. However there seems to be some controversy surrounding the usage of autorelease on the iPhone. I personally don't see a problem with it unless it's used in a tight loop that iterates many many times in a short period of time.
self.myProperty =[[myArray mutableCopy] autorelease];
If you're using CoreData, then ideally you should be using a NSFetchedResultsController to manage the data for the tableview. (You did ask for the "correct" way :-)
You'll end up with a more memory efficient app.
See the iPhoneCoreDataRecipes Sample for a good example
I have this code in one of my classes:
- (void) processArray
{
NSMutableArray* array = [self getArray];
. . .
[array release];
array = nil;
}
- (NSMutableArray*) getArray
{
//NO 1:
NSMutableArray* array = [[NSMutableArray alloc]init];
//NO 2:
NSMutableArray* array = [NSMutableArray array];
. . .
return array;
}
NO 1: I create an array and return it. In the processArray method I release it.
NO 2: I get an array by simply calling array. As I'm not owner of this, I don't need to release it in the processArray method.
Which is the best alternative, NO 1 or NO 2? Or is there a better solution for this?
The method should return an autoreleased array, NO 2 is the better choice. The reason for this is that when you call the method with
NSMutableArray* array = [self getArray];
you will expect as a matter of convention to not have to release the array. If you want to take ownership of it, you retain it, but otherwise you shouldn't have to care about it. In Cocoa, you only take ownership by explicitly sending alloc or retain or copy (or new). Since the processArray method doesn't do that, it shouldn't have to take care of releasing the array.
So you should use NO 2, and also you should remove these two lines:
[array release];
array = nil;
If the array and its contents use a lot of memory or its used lots of times, you'll want to release them straight away, so use option 1. According to the Objective-C guidelines, you'll want to prefix the word "new" to your subroutine name instead of "get" in that case.
If on the other hand, you want to reduce the number of lines of code that say simply [array release]; or similar then use option 2.
It is simply a balance between reducing lines of code, and reducing unnecessary temporary memory use.
Whilst the autorelease pool will help in reducing memory leaks and make your code smaller, sometimes you need to explicitly release everything as it goes out of use to keep the use of memory down.
HTH
EDIT
Ah - I stand corrected. Reading the iPhone version of the Memory Management Programming Guide for Cocoa I see that the iPhone guidelines are to use a prefix of "new..." so for example "newArray" in this case, if the caller is supposed to manually release and NOT a prefix of "create...". "Creating" can refer either to creation of manually released or of automatically released objects and so would be ambiguous. Text corrected above.
- (void) processArray
{
NSMutableArray* array = [[self getArray] retain];
//Now you are the owner of array, so you take care to release it
. . .
[array release];
array = nil;
}
- (NSMutableArray*) getArray
{
//create a new array
//temporarily the method owns the array
NSMutableArray* array = [[NSMutableArray alloc]init];
//fill in here with elements or what you want
..........
[array autorelease];
//autorelease here says "I don't own the result
//if anyone cares about it, he should retain it himself
return array;
}
So in short when you create new objects you should autorelease them before returning.
Because if the calling method wants to use the result, the calling method should take care
of retaining and releasing the result.
It's always good to run the Klang static analyzer for this issues, when you are not really sure in your retaining/releasing code : http://clang-analyzer.llvm.org/
I'm doing an iPhone application which uses a navigation control to browse through some data. This data is stored in a sqlite database and I have a class which gets it and returns it in a NSMutableArray of NSStrings.
The problem is that in the first screen of the navigation everything works prefectly, but in the second screen (another view which is pushed) the same code fails because the NSMutableArray gets corrupted. In the debugger I can see that it is returned correctly, but when it's time to use it the pointers have become corrupted and the application crashes.
I have put breakpoints in all my functions, and I can't see anywhere where it can get corrupted. And as the first view, which uses the same exact code, even accesing the same eact tables, works correctly I don't really know where to look.
If anyone want to have a look at the code I have uploaded it to my site: http://sachafuentes.com/iBacus.zip
Thanks in advance.
UPDATE:
The problem lies in the function where I get the data, which looks like (this is a simplified version with some pseudo-code).
-(NSMutableArray *) getPaises {
NSMutableArray * paises;
paises = [[NSMutableArray alloc] init];
while( get new row ) {
NSString *aPais = get the value;
[paises addObject:aPais];
[aPais release];
}
return paises;
}
If I comment out [aPais release] everything works, but to me this looks like a memory leak, as the NSString won't be released.
Okay, here's the problem:
NSString *aPais = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 0)];
By convention, any time that you see an alloc and an init, you need a release somewhere down the road.
By convention, any time that you use an xWithX: style method, the resulting object will be released for you.
Therefore, this statement:
[aPais release];
will cause your method to crash, as the object is released before it should be. Just remove this line, set your NSMutableArray instance to be autorelease-d and you should get better results.
Look for wrong memory management, that's the likeliest cause for crashes. I think you release your objects somewhere where you shouldn't and therefore you have dangling pointers in the array.
Update1
[aPais release] is wrong, as you don't retain it anywhere in this method. Returned values should always be autoreleased. You should have the same amount of retain as release in your code.
(Some people argue that a retain can also be an alloc init, but I always try to use alloc init autorelease, but this is a matter of style.)
BTW
You should autorelease your array, you're only retaining it here with [[alloc] init].
Any object that you alloc and init must be release-d when you're finished with it, or you will have a memory leak.
Since you are passing the reference outside the scope of the getPaises method, you must autorelease the NSMutableArray, or you will have a memory leak:
paises = [[[NSMutableArray alloc] init] autorelease];
Can you please clarify the step here:
NSString *aPais = get the value;
It's not clear what happens in "get the value" and I suspect this is one cause of instability.
I see that the code is (verbatim)
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *aPais = [NSString stringWithUTF8String:
(char*)sqlite3_column_text(compiledStatement, 0)];
[paises addObject:aPais];
[aPais release];
}
...and it's exactly as #gs puts it. aPais is autoreleased and should not be released.
You can also use a convenience constructor to initialize the NSMutableArray:
NSMutableArray *paises = [NSMutableArray array];
This is equivalent to doing:
NSMutableArray *paises = [[[NSMutableArray alloc] init] autorelease];