I have the following method:
-(NSMutableArray *)someArray{ // line 1
if(self.someArray == nil){ // line 2
self.someArray = [[NSMutableArray alloc]init];
}
return self.someArray;
}
I had this in non-ARC, and it works fine: If self.someArray in line 2 is nil, then go ahead and instantiate it.
However, after I switched to ARC, when it gets to line 2, it goes back to line 1, and the loop continues.
Any help will be greatly appreciated.
Thanks.
The proper form is
#synthesize someArray = _someArray;
- (NSMutableArray *)someArray {
if (!_someArray) {
_someArray = [NSMutableArray array];
}
return _someArray;
}
self.someArray calls the getter, hence the infinite loop. use _someArray within that method instead (assuming you're using the automatic ivar provided by the property. Otherwise, use whatever your backing variable is).
What is happening is that you are calling the accessor method inside the accessor. But if every accessor calls itself, you'll never break this cycle.
Use the auto synthesized property to avoid this:
-(NSMutableArray *)someArray{ // line 1
if(_someArray == nil){ // line 2
_someArray = [[NSMutableArray alloc]init];
}
return _someArray;
}
Related
This is an implementation section of a class named "Model". Here I recursively call call the setDictionary method upto 3 layers, which raises an exception (NSMutablearray mutated while being enumerated) this exception can be avoided if I use for loop istead of forin, I would like to understand how this error occurs...Can any one help...Please dont reply with some links that point to some definition, I already read lots of documentation and I dont understand how the exception is raised in this situation.
#implementation Model
#synthesize arraySubOptions,boolHasSub;
- (instancetype)init
{
self = [super init];
if (self) {
boolHasSub = NO;
arraySubOptions = [NSMutableArray new];
}
return self;
}
-(void)setDictionary:(NSDictionary*)dict{
boolHasSub = [[[dict objectForKey:#"key_has_sub"] nullCheck:[NSString class]] boolValue];
if (boolHasSub) {
NSArray * arrayDict = (NSArray*)[self loadDataFromDB];
if(arrayDict && (arrayDict.count>0) ){
for (NSDictionary * dict in arrayDict) {
Model * objOption = [Model new];
[objOption setDictionary:dict];
[arraySubOptions addObject:objOption]; /*This is the line that raises the exception. It raised */
}
}
}
}
#end
Your method
[self loadDataFromDB]
should be altering your arrayDict, so, when you reach
[objOption setDictionary:dict];
is entering twice in that function, modifying your arrayDict and launching this exception.
Doing it with 'for' instead of 'foreach' works because you set the limits of your loop and it doesn't reach any exception if your limit isn't out of bounds. (i > arrayDict.count)
[self loadDataFromDB] returns an array which gets deallocated when the method call ends, since the object was created inside the method. So copying the returned array did the trick.
[[self loadDataFromDB] copy]
I am looking to get an NSString value from a Text Field and add it to an array, I want to build an array with many strings in it ex:
[hello, goodbye, too soon].
This is my current solution:
- (IBAction)submitButton:(id)sender {
NSMutableArray *wordArray = [[NSMutableArray alloc] init];
NSString *input = textField.text;
[wordArray insertObject:input atIndex:arrayIndex];
arrayIndex++;
}
This works for the first item in the array, but when I press submit again it reinitializes.My issue is how do I initialize the NSMutableArray to use in the button function, without having it in there so that it doesn't initialize every time. Thank you
Your are using a local array that disappears as soon as the submitButton method is finished.
Make your wordArray an instance variable and initialize it once in viewDidLoad. Then in your submitButton: method (and any others), you reference the instance variable instead of creating local arrays.
Honey's answer is almost, but not, correct.
Your code uses a local variable in your submitButton method, and creates a new, empty array each time the method gets called. Both of those things are wrong.
Honey's answer has you create a different local variable in viewDidLoad. That's also wrong.
You need to make wordArray an instance variable or property of your class. If you class is called ViewController, say, it might look like this
#interface ViewController: UIViewController;
#property (nonatomic, strong) NSMutableArray *wordArray
...
#end
And then initialize it in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
self.wordArray = [[NSMutableArray alloc] init];
}
Then in the rest of your program refer to self.wordArray, the property.
Here's the solution,
#implementation ViewController{
NSMutableArray *_wordArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
_wordArray = [[NSMutableArray alloc] init];
}
- (IBAction)submitButton:(id)sender {
NSString *input = textField.text;
[wordArray addObject:input];
}
You was re init the array each time you make the action, which will let you always save the last value of the textfield.
but this creates an array as global variable so that you can add all the values entered in textfield.
Hope this help you :)
Is it better to initialize an NSArray in viewDidLoad when the program first starts up, or define the NSArray only if a condition is met?
Basically, I initialized an NSArray in an IF condition of one of my methods. This method may be called multiple times, and want to know if it's better on memory if the NSArray is created and destroyed in the method, or if it's better to define it once in viewDidLoad and reference it in the method?
If I'm not clear, please let me know.
Thanks
Create any data collection only when you need it, this way you make sure that the program/screen is initially launched quickly. This is called as lazy loading, this approach should be followed whenever possible.
If you are using NSMutableArray and managing this in run time, you can do something like this for lazy loading, and clearing it from memory when not needed. Add helper methods to add and remove objects from an array, array is created automatically when needed and removed from memory when it is empty.
- (void)addObject:(NSObject *)value
{
if (value == nil) return;
if (_collection == nil) {
_collection = [[NSMutableArray alloc] init];
}
[_collection addObject:value];
}
- (void)removeObject:(NSObject *)value
{
if (value == nil) return;
[_collection removeObject:value];
if ([_collection count] == 0) {
[_collection release], _collection = nil;
}
}
A XML parser is trying to alloc its delegate's NSMutable array called masterCodeList. From the following code, you'll see that this fails. (I am a total newbie.)
if (dataController.masterCodeList == nil){
dataController.masterCodeList =[[NSMutableArray alloc] init];
if (dataController.masterCodeList == nil) {
NSLog(#"the init of the mutable array did NOT work");
}
}
I get the the init of the mutable array did NOT work message every time. I am importing the dataController header.
#import "CodeDataController.h"
I am getting no other error message, the parser is parsing fine and the app is running smoothly without content.
Thanks in advance.
What does your declaration of masterCodeList look like?
Is it a property, and is it synthesized, or are you making your own setter/getter?
An alternative would be to try using an intermediate placeholder, ie:
NSMutableArray *temp = [[NSMutableArray alloc] init];
[dataController setMasterCodeList:temp];
and see if that sets your array correctly.
(note: that code may or may not have leaks)
could you post your implementation of the dataController object in this class, and its attributes from the other class?
you also may want to try using the isEqual method instead of == nil.
I must have misunderstood some of the memory management rules, because when I try to fix a memory leak, the App crashes. Let me show you some code:
calendarRequestLog is a property of type MutableDictionary in a singleton object, that exists as long as the App runs. Here's the declaration in the .h file:
#property (nonatomic, retain, readonly) NSMutableDictionary *calendarRequestLog;
I allocate it with (in init):
calendarRequestLog = [[NSMutableDictionary alloc] init];
I fill it with this (notice the retain, that creates the memory leak):
[calendarRequestLog setObject:[[NSMutableArray arrayWithObject:delegate] retain] forKey:date];
I sometimes access it with this:
NSMutableArray* delegates = [calendarRequestLog objectForKey:date];
if(delegates != nil) {
// add delegates
}
I empty it with this:
NSMutableArray* delegates = [calendarRequestLog objectForKey:date];
if(delegates != nil) {
for (id <ServerCallDelegate> delegate in delegates) { … }
// clear the request from the log
[calendarRequestLog removeObjectForKey:date];
}
Here's the code that crashes when I remove the retain above:
NSMutableArray* delegates = [calendarRequestLog objectForKey:date];
if(delegates != nil) {
if([delegates containsObject:delegate]) // crash
[delegates removeObject:delegate];
}
It crashes because delegates is deallocated but not nil. To be more precise, I get an EXC_BAD_ACCESS Exception.
All these methods may be called in different orders or multiple times.
I cannot figure out, why this happens. I thought, collections are supposed to retain their objects - as this array-object (delegates) is still in the collection, it should not be deallocated. Other code cannot be responsible, I showed you all occurrences of calendarRequestLog.
I appreciate all the help I can get!
#Edit
I think I got it.
I call the crashing method when the delegate gets deallocated, so that I do not call the delegate per accident later.
But: I retain the delegates in my calendarRequestLog, so it cannot get deallocated as long as this doesn't get called:
// clear the request from the log
[calendarRequestLog removeObjectForKey:date];
...which in turn, deallocates the delegate and calls the crashing method. As the calendarRequestLog has removed the delegates, but not yet the key, we crash.
Ok, I will solve this differently. Thanks for all the comments - thanks to you, I looked elsewhere!
Did you try retaining when fetching so nobody releases your object while you're using it?
NSMutableArray* delegates = [[calendarRequestLog objectForKey:date] retain];
if(delegates != nil) {
if([delegates containsObject:delegate]) // crash
[delegates removeObject:delegate];
}
[delegates release];
Common practice is the following, because you already retain in the .h file:
//create local instance, then copy that to the class wide var
NSMutableDictionary *_calendarRequestLog = [NSMutableDictionary alloc] init];
self.calendarRequestLog = _calendarRequestLog;
[_calendarRequestLog release];
Also, I don't really understand why you would retain here:
[calendarRequestLog setObject:[[NSMutableArray arrayWithObject:delegate] retain] forKey:date];
Why not just change that to:
[calendarRequestLog setObject:[NSMutableArray arrayWithObject:delegate] forKey:date];
Write instead
calendarRequestLog = [[NSMutableDictionary alloc] init];
this
self.calendarRequestLog = [NSMutableDictionary dictionary];
and try to use property instead ivar