My NSMutableArray lOfSegments, declared as IVAR, get populated correctly. During the debug it shows 4 object in the array.
for (int x=0; [arrayOfSegmentsTcIn count]>x; x++) {
NSDictionary *segmentDic=[[NSDictionary alloc] initWithObjectsAndKeys: [arrayOfSegmentsNumbers objectAtIndex:x],#"segment",[arrayOfSegmentsTcIn objectAtIndex:x],#"tc_in",[arrayOfSegmentsTcOut objectAtIndex:x],#"tc_out", nil];
[lOfSegments addObject:segmentDic];
[myDMXML.segments addObject:segmentDic];
}
[self.xmlTCLable setStringValue:[myDMXML startTimeCode]];
[self.xmlDurationLable setStringValue:[myDMXML duration]];
[self xmlValidationCheck];
NSLog(#"arrayController:%#",[lOfSegments valueForKey:#"segment"]);
[self.tableViewOutlet reloadData];
NSLog list the array correctly but when reloadData is executed the code jumps to
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [lOfSegments count];
}
The array is null.
The Object is initialised in viewDidLoad as
lOfSegments = [[NSMutableArray alloc]init];
Please Help!
First, I recommend making your code more clear here by using self.lOfSegments rather than directly accessing an ivar. (The fact that the ivar lacks a leading _ is very suspicious as well, and raises the question of whether this is even the variable you think it is.)
On the assumption that this is the variable you think it is, and that you have overridden the standard behavior to make the ivar match the property or created explicit ivars (neither of which you should do), there are several common causes for this kind of problem:
The most likely cause is that you called your initialization code prior to viewDidLoad and then viewDidLoad blew away the array. Many things can run prior to viewDidLoad, and viewDidLoad can run more than once (at least this used to be true; I'd have to study whether the view-loading changes in iOS 6 made it guaranteed to be run once.)
You have some other way reset lOfSegments between the time your initialization code ran and the time reloadData ran. If you would reliably use self. then you could override setLOfSegments: so you could log this. Or you could mark this property readonly so you could prevent it. Thats one of many reasons that you should use properties, not ivars.
The setting code failed to run before reloadData. Ensure that the log statement actually printed prior to getting to reloadData and is on the same queue (the queue identifier will be part of the NSLog output in brackets). I don't think this is likely given your description, but it is a common problem.
There are two instances of this object. Make sure that the object that ran your initialization code is the same object that ran reloadData. This is a more common mistake then you may think. Log self and make sure the memory address is the same in both cases.
looks like you have variable with same name lOfSegments in method viewDidLoad. So in viewDidLoad you use stack variable, in numberOfRowsInTableView - instance variable.
Or maybe tableViewOutlete.dataSource pointing on different viewController
Related
Here's my current situation:
I have a NSMutableArray named dictKeyArray which I assign a property with #property(nonatomic,retain)NSMutableArray *dictKeyArray
I synthesize my mutable array in the implementation file.
Later, I have a dictionary name storeDict. I assign all the keys of the dictionary to the dictKeyArray like so:
dictKeyArray = [[storeDict allKeys] mutableCopy];
Now I use this dictionary later in my implementation file. However, when it comes to releasing it, I release it once in my dealloc method. When checking with instruments, a leak shows up! Why is dictKeyArray leaking? Should I be using assign instead of retain?
I'm still not clear on what the difference is exactly...
thank you!
You have to send it an
[[[storeDict allKeys] mutableCopy] autorelease];
Just to make this clear: mutableCopy does the same as alloc meaning you are claiming ownership of the object in question. You have to decrease the retainCount by one.
By the way: You should use the accessor you wrote for it. You are just assigning it to your iVar at the moment. If you want to make your accessors work, you will have to use something like
object.dictKeyArray = ...;
in general. Or here (as mentioned by dreamlax)
self.dictKeyArray = ...;
because you are referring to an object of this specific class the code is in.
Only this way you are ensuring your object is properly retained by your accessor. Otherwise writing the accessor code doesn't make sense at all because it never gets called.
Please note: As Josh said in the comments, your code should be valid (at least from my point of view). What I suggested is a solution that is not as error-prone as yours because you adhere to the rules (could save you from headache in the near future).
You should be using self.dictKeyArray = .... Without the self. you are accessing the instance variable directly, bypassing any memory management benefits of properties, but, remember that you own the result of mutableCopy, and assigning to a property that also takes ownership will result in double-ownership, so use:
self.dictKeyArray = [[[storeDict allKeys] mutableCopy] autorelease];
NSArray *array = [dictionary objectForKey:#"field"];
and
NSArray *array = [[NSArray alloc] initWithArray:[dictionary objectForKey:#"field"]];
I see both kind of approaches very frequently in objective C code.
When tried to understand, I found both of them used in similar situation too, which makes contradiction. I am not clear on when I should use 1st approach and when 2nd one?
Any idea?
Detailed explanation and useful references are moms welcome.
First off, those two examples are doing slightly different things. One is retrieving something from an existing dictionary and one is creating a new array by retrieving something from an existing dictionary (the value of that key is an array).
But, if you're asking the difference between getting objects by alloc vs. convenience methods. ([NSString alloc] init vs [NSString stringWith ...), by convention, you own anything that you call alloc, new copy or mutableCopy on. Anything that you call that is not those, is autoreleased.
See the memory guide here. Specifically, look at the rules.
Getting an autoreleased object means it will go away at some point in the near future. If you don't need to hold onto outside the scope of that function, then you can call autorelease on it or use one of the convenience methods that's not alloc, etc...
For example:
// my object doesn't need that formatted string - create the autoreleased version of it.
- (NSString) description {
return [NSString stringWithFormat:#"%# : %d", _title, _id];
}
// my object stuffed it away in an iVar - I need the retained version of it. release in dealloc
- (void) prepare {
_myVal = [[NSString alloc] initWithFormat:"string I need for %d", _id];
}
In the first example, I created a convenience methods for others to call, my class doesn't need that object beyond the scope of that method so I create the autoreleased version of it and return it. If the caller needs it beyond the scope of his calling method, he can retain it. If not he can use it and let it go away. Very little code.
In the second example, I'm formatting a string and assigning it to an iVar variable that I need to hold onto for the lifetime of my class so I call alloc which will retain it. I own it and releasing it eventually. Now, I could have used the first version here and just called retain on it as well.
You have a fundamental misunderstanding of allocations versus instance methods.
The first example, NSDictionary's -objectForKey method, returns id, not an instance of NSDictionary, therefore it does not allocate or initialize the variable.
The second, however is the classic retain part of the retain-release cycle.
The two methods are fundamentally equal (if we are to assume that array is alloc'd but empty in the first, and nil in the second), and both get ownership of the array object. I would go with the second, as it guarantees a reference, and it's shorter.
What I think you're confusing this with are new and convenience methods. Convenience methods (like NSNumber's +numberWithInt:, NSString's +stringWithFormat:, and NSMutableArray's +array), return an autorelease instance of the class (usually). New takes the place of alloc and init in just one word.
I have been working with Objective-C for a month approximately but regretfully I'm still a complete dummy in memory management so I need your advice. I pass an array from one file to the other like this
BidView *bidView = [[[BidView alloc] init] autorelease];
NSLog(#"%i",[bidView.seatsForTableCreated retainCount]);
bidView.seatsForTableCreated = [NSArray arrayWithArray:seats];
NSLog(#"%i",[bidView.seatsForTableCreated retainCount]);
[self.navigationController pushViewController:bidView animated:YES]; `
NSLog tells me that retain count of seatsForTableCreated has raised from zero to two. Then, when I quit the BidView screen (without doing anything with seatsForTableCreated array) I' m doing the following:
NSLog(#"%i",[seatsForTableCreated retainCount]);
[seatsForTableCreated release];
NSLog(#"%i",[seatsForTableCreated retainCount]);
it's quite unclear for me. Now NSLog tells me (both times) that retain count is 1. Then I repeat this procedure (running the same application I mean) and each time things are the same:0-2-1-1. So my questions are:
1)Why 0 to 2? Why retain count increases to 2 not to 1?
2)why then it drops to 1 without being impacted in any way?
3)Why it still remains 1 after i've released it?
4)How would you manage the memory in such a case?
Great thanks in advance
First and foremost. Don't call nor use retainCount for nothing, think about this property as private and only the OS can call. To check if you have a memory leak you should use Instruments.
Seems like you've created an autoreleasing ([NSArray arrayWithArray:seats]) object, so you can't manually release it.
And use the Allocations Instrument to really check if you have a memory leak.
My advice assumes you are using Xcode 4+ and you are not using ARC,
command+shift+B will analyse your memory management (and dead stores and such). I think you got it right. Don't worry about the retain counts so much until you get a complaint from Analyze or find leaks with Instruments. I am not sure how reliable retain counts are. I have seen comments on SO saying not to rely on them.
You are following the rules well
New, Alloc, Copy, Retain --> You will need to release this object when you are done with it.
I am also assuming in BidView.h your property is declared as
#property(nonatomic, retain) NSArray * seatsForTableCreated;
So releasing that in the dealloc method in BidView.m is good memory management
EDIT
It works when even though you don't allocate seats for table created because.
self.seatsForTableCreated = ... will retain whatever object you are setting there.
So if you have a property with (retain) in the declaration, you can consider
self.property = object;
as setting property and retaining it. The properties were added to objective-C to reduce similar code being in every class.
A property in .h
#property (nonatomic,retain) NSObject * property; // don't name your properties property..
Compiler will create 2 methods for you automatically when you #synthesize in the .m
-(void)setProperty:(NSObject*)newP
{
[newP retain]; // retains the new object so it sticks around for line 3
[property release]; // releases previous property
property = newP; // set the property to the object retained in line 1
// property is now same as newP and you are responsible for releasing it
// -(void) dealloc is where you should release it
}
// Note, the compiler may not create the exact same code as above when creating the //setProperty method. If it does, it could be subject to change.
-(NSObject*)property
{
return property;
}
I tried to figure out why Analyze isn't catching the issue when you don't release your property, but haven't. That is confusing and I want to explore it further.
I just wrote some code. It has my own custom made class. In that custom made class called 'WonderfulNumbers' I have a method that looks like this
- (NSString *)storedNumberAsString {
NSString *stringToReturn = [[NSString alloc]initWithFormat:#"Hello World"];
return [stringToReturn autorelease];
}
I obviously then #import "WonderfulNumbers" into the main and etc
then in my main I have an IBAction.
it reads like the following
-(IBAction)displaySomeText:(id)sender {
WonderfulNumbers *myNumber = [[WonderfulNumbers alloc]init];// Step 1
NSString *numberString = [myNumber storedNumberAsString];// Step 2
[textView insertText:numberString];// Step 3
//textView is a variable of NSTextView.
[myNumber release];// Step 4
}
I get the step by step process, and the logic behind this.
What I like to know and try to reassure to my self is what exactly is happening at step 2.
I understand Step 1, 3 and 4.
But step 2, I crated an NSString variable called 'numberString' and it obviously holds the object called 'myNumber' with the method described above applied to it. Makes sense.
What I want to know is, I never allocated or initialized the 'numberString' object of NSString class. How am I able to then use it.
I know I don't release it since it's never allocated .. but did I initialize it by just doing [myNumber storedNumberAsString]; ?
A slight explanation would be awesome. Thank's to those that reply.
P.S. I know that everything in objective-c is an object but just for the sake of this argument, since 'numberString' is not technically "created by allocate and init" is it right to call that a variable?
I think I know the differences between the two but just want reassurance.
Thanks.
You are initializing NSString *stringToReturn to the return value of [myNumber storedNumberAsString]. Inside storedNumberAsString you can see that it returns an NSString reference, properly allocated and all, so it's fine to use.
The key here is autorelease, which causes the object to be released automatically “sometime later” (actually when the topmost autorelease pool is released, which, unless you changed it yourself, tends to happen after each iteration of the event loop).
The convention in Objective-C is that if you alloc or retain an object, or get an object from a method whose name begins with new, copy, or mutableCopy, you are responsible for releasing it. Otherwise you can assume it will be released by someone else (e.g., later via autorelease). Since storedNumberAsString does not begin with new, copy, or mutableCopy, you don't need to release it. Meanwhile the implementation of storedNumberAsString must ensure that the object it allocs gets released -- in this case that is done by calling autorelease on it.
In objective-c, I have a utility class with a bunch of static methods that I call for various tasks. As an example, I have one method that returns an NSArray that I allocate in the static method. If I set the NSArray to autorelease, then some time later, the NSArray in my calling method (that is assigned to the returned pointer) losses it's reference because the original form the static method is cleaned up. I can't release the NSArray object in the static method because it needs to be around for the return and assignment.
What is the right way to return an object (like the NSArray) from a static class, and have it hang around for the calling class, but then get cleaned up later when it is no longer needed?
Do I have to create the object first in the caller and pass in a pointer to the object and then return that same object form the static method?
I know this is a basic O-O problem, I just never had this issue in Java and I do not do much C/C++.
Thanks for your help.
Your autorelease is correct in the return just retain it when you call the static method.
NSArray *data = [[StaticClass getArray] retain];
If you have a property for the place your assigning the return value to, you can just do self.data = .. and the retain is automatic.
Please take the time to read over the rules. These apply to all of the frameworks you'll be using, and should apply to your code as well. Burn these into your head, and they'll become second nature. Thankfully, it's not complex, rather simple.
It's quite simple. If you do not own an object, it will go away at some indeterminate point in the future. In your case, the "indeterminate" point is when the autorelease pool gets drained, which in the normal case, is at the end of processing the current event.
If you want an object to hang around, you need to own it. The memory management rules referred to by jer will tell you exactly how you get ownership of an object. In this case, you need to retain the object. You must then, of course, release it later when you have done with it.
Regards your comment to Matt's answer. Your code is this:
for (NSString * date in dateList)
{
[historyList addObject:[[BIUtility historyForDate:date] retain]];
}
and
+ (NSArray *) historyForDate:(NSString *)date
{
NSMutableArray * ret = [[[NSMutableArray alloc] init] autorelease];
}
The first thing you need to know is that collections retain their members, so, in fact, your retain of the historyForDate is unnecessary. You don't want to own that object, historyList does. If it's disappearing, it's probably because historyList itself is being deallocated (because you don't own it) or is nil.
By the way, historyForDate: does nothing with the date. Is that correct?