I basically have have a custon subclass of an UIViewController, which has a NSMutableArray called waypoints. I initialise it in the -(void)viewDidLoad method of the controller with
waypoints = [[NSMutableArray alloc] init];
Later, in a method which gets called via a presentedViewController with some parameters including a NSMutableDictionary as waypointData, I call
[waypoints insertObject:waypointData atIndex:0];
and I also tried
[waypoints addObject:waypointData];
But neither seems to work!
I logged some stuff there to make it more clear. The parameters get transmitted correctly and the NSMutableDictionary saved under waypointData is the correct content it should be. Logging the waypoints array before the insertion shows it empty (which is correct; app got launched; no data added yet) and after the insertion it's still empty. The log:
2014-02-19 14:40:11.050 xxx[xxx] waypoints before insertion: (null:)
2014-02-19 14:40:11.051 xxx[xxx] INSERT WAYPOINT
2014-02-19 14:40:11.052 xxx[xxx] waypoints after insertion: (null:)
INSERT WAYPOINT gets logged directly before the insertion, so the program routine is really executing the insertObject:atIndex: method.
TL;DR:
Even though insertObject:atIndex: (and -addObject:) for an NSMutableArray get called the object won't get inserted in the array.
EDIT:
This method gets called in -viewDidLoad too:
- (void)loadWaypoints {
id unarchivedObject = [NSKeyedUnarchiver unarchiveObjectWithFile:[[self applicationDocumentsDirectory] stringByAppendingString: kAppDataFilePlistName]];
waypoints = (NSMutableArray *)unarchivedObject;
}
unarchivedObject of course is NULL if there hasn't been anything saved yet. Thanks to 0x7fffffff.
Check your waypoints NSArray it shouldn't be nil when you call at [waypoints addObject:waypointData];
easiest way to make sure your 'waypoints' array isn't nil is doing this:
if (!waypoints)
{
waypoints = [NSMutableArray new];
}
[waypoints insertObject:waypointData atIndex:0];
or
if (!waypoints)
{
waypoints = [NSMutableArray new];
}
[waypoints addObject:waypointData];
It sounds like your waypoints array is nil. Post your header file, including the declaration of waypoints. Post your whole viewDidLoad method where you create the empty array.
The 2 most likely causes I can think of are that you declared waypoints as weak, or that you have a local variable waypoints in your viewDidLoad and you're creating an empty array in the local variable but not saving it to the instance variable.
Set a breakpoint in viewDidLoad at the line that creates the empty array. Step over it and make sure your array is being created. Then right-click on the variable down in the variables section of the debugger window and add a watchpoint to that variable. If it is getting cleared out then the breakpoint will cause your program to break at the offending line.
(My post assumes that you are using ARC. Are you?)
Please use following code:
if(waypoints == nil){
waypoints = [[NSMutableArray alloc] init];
}
[waypoints addObject:waypointData];
Related
I've made a NSMutableArray a property on my view controller, which holds some core data objects for users.
When the user presses a button , I clear out the contents of the mutable array with a while loop,
while (self.mArray.count != 0){
[context deleteObject:self.mArray[0]];
[self.mArray removeObjectAtIndex:0];
}
After the while loop, I reinit the array:
self.mArray = [[NSMutableArray alloc] init];
I know it isn't necessary since there should be zero objects left in the array, but regardless, when I reinitialize the array, and then check the class of the array in the debugger, I get __NSArrayI, which is corroborated by an exception thrown when I attempt to add an object into self.mArray right afterwards.
I've looked for any other references to my array, but I've always passed around [self.mArray mutableCopy] as arguments to other methods, and I never cast it as an NSArray. I just don't understand how calling [[NSMutableArray alloc] init] would initialize the array as an immutable array.
What am I missing?
It's likely that you have declared mArray as copy in the property declaration. Change that to strong.
I feel like there is a more regulation way to do what I am doing in, either by some iOS specific thing, or pattern I'm aware of. I'm trying to create an NSMutableArray variable, that essentially acts as temporary storage for a logger class. Each time the array is accessed, I want to either lazily instantiate it, or set it to nil. The way I am thinking of doing it seems a little hacky and I'm looking for some input?
- (NSMutableArray)myArray {
if (!_myArray) {
_myArray = [[NSMutableArray alloc] init];
} else {
_myArray = nil;
}
return _myArray;
}
The effect I'm hoping to achieve is using a logger that is logging details about network requests - http codes, URLs, repsonse times, etc. I want the logger to amalgamate all this output in this storage array. Later on, when I'm hitting an API, I want to take the contents of this array, and send it up to the API, and I also want the array to reset (so the array is essentially a log of network request data since the last time the app hits the API, versus a log of what has happened since the app launched.
I realise that I could do this manually by niling the array when I access it, but I'm trying to do this in a more of a plug and play way, where it you don't need to worry if someone forgets to nil the array etc
The effect that you are trying to achieve is perfectly legitimate, but you shouldn't try to achieve it with a getter alone: the very fact that a simple getter could reset something back to nil would be counter-intuitive to your readers.
Instead, you should make two methods - one to prepare the array, and another one to harvest it, and replace with a fresh nil:
- (NSMutableArray*)myArray {
if (!_myArray) {
_myArray = [[NSMutableArray alloc] init];
}
return _myArray;
}
- (NSMutableArray*)resetArray{
NSMutableArray *res = _myArray;
_myArray = nil;
return res;
}
Now the sequence of operations becomes intuitively clear: you get myArray as many times as you wish, add as many items as you need, and then when you are done call resetArray. This would get you a complete array with all the data, and reset the object to be ready for the next call:
for (int col = 0 ; col != 10 ; col++) {
[log.myArray addObject:[self getDataForIndex:col]];
}
NSMutableArray* logArray = [log resetArray];
What you're doing doesn't make any sense to me.
Creating it empty if it doesn't exist makes sense.
Setting it to nil if it does exist does not make sense.
The usual pattern for lazy loading is to use a property with a getter:
#property (nonatomic, retain) NSMutableArray * myArray;
and then the implementation:
//Custom getter
-(NSMutableArray*) myArray;
{
if (!_myArray)
_myArray = [[NSMutableArray alloc] init];
return _myArray;
}
Then you ALWAYS refer to the array using the getter. If it hasn't yet been created, the getter creates and returns the empty array. If it does exist, it returns the existing one.
I am trying to check if the NSMutableArray has a specific object, before adding the object to it, if exists then don't add.
i looked over many posts explaining how to do this, managed to implement it like this, but it always gives me that the object "doesn't exist", though i already added it !
//get row details into FieldLables Object
AllItemsFieldNames *FieldLabels = feedItems[row];
// object to hold single row detailes
AllItemsFieldNames *SelectedRowDetails = [[AllItemsFieldNames alloc] init];
SelectedRowDetails.item_name = FieldLabels.item_name;
//SelectedRowDetails.item_img = FieldLabels.item_img;
SelectedRowDetails.item_price = FieldLabels.item_price;
//NSLog(#"item has been added %#", SelectedRowDetails.item_name);
//NSLog(#"shopcartLength %lu", (unsigned long)SelectedFieldsNames.count);
if([SelectedFieldsNames containsObject:SelectedRowDetails])
{
NSLog(#"Already Exists!");
}
else
{
NSLog(#"Doesn't Exist!");
[SelectedFieldsNames addObject:SelectedRowDetails];
}
I can display all object from the NSMutableArray into a table, what i need to do in the above code is stop the addition of duplicate objects.
The first method listed on the NSArray documentation under the section "querying an array" is containsObject:. If it's not working, that suggests that your implementation of isEqual: is not correct. Make sure you follow the note in the documentation:
If two objects are equal, they must have the same hash value. This
last point is particularly important if you define isEqual: in a
subclass and intend to put instances of that subclass into a
collection. Make sure you also define hash in your subclass.
You might also consider using an NSSet since you can't add duplicates to that. Of course, this would also require a working version of isEqual:.
Sets are composed of unique elements, so this serves as a convenient way to remove all duplicates in an array.
here some sample,
NSMutableArray*array=[[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4", nil];
[array addObject:#"4"];
NSMutableSet*chk=[[NSMutableSet alloc ]initWithArray:array]; //finally initialize NSMutableArray to NSMutableSet
array= [[NSMutableArray alloc] initWithArray:[[chk allObjects] sortedArrayUsingSelector:#selector(compare:)]]; //after assign NSMutableSet to your NSMutableArray and sort your array,because sets are unordered.
NSLog(#"%#",array);//1,2,3,4
I'm trying to use the parse.com data browser to inset a new string array into my code.
So if I've got a code with an array of #"blue", #"yellow", #"black", nil then how can I change it to #"white", #"gold", #"brown", nil ?
In the app, I have the user press a button and one of said string value appears at random. I would like to put a new array on a backend to have new values so that I don't have to update the app every time.
Is there an example of how to do this? I haven't been able to get the Data Browser to replace the array in my code with the array in the data browser.
I've got:
PFQuery *query = [PFQuery queryWithClassName:#"colorArray"];
self.colors = [query findObjects];
But it crashes when I try to retrieve the values of the array when it gets to this part of the code in a later method -
NSUInteger index = arc4random_uniform(self.colors.count];
self.colorLabel.text = [self.colors objectAtIndex:index];
self.colors, by the way, is synthesized from the header file as an array. It looks like the code doesn't understand the "index" part of the equation when it tries to set the self.colorLabel.text using the obectAtIndex
The crash is "-[PFObject length]: unrecognized selector sent to instance 0xcb56740".
Am I doing this right?
self.colors is an array of PFObjects - not NSStrings
That is why this line fails:
self.colorLabel.text = [self.colors objectAtIndex:index];
What you need is something like:
NSUInteger index = arc4random_uniform(self.colors.count];
PFObject *colourPFObject = [self.colors objectAtIndex:index];
self.colorLabel.text = [colourPFObject objectForKey:#"columnNameForColour"];
Don't forget to change columnNameForColour to whatever name you call your colour column in your the Parse.com colorArray class
See the #Carl Veazey comment.
{colors = (Red,Blue,Black);}
is from the description method of PFObject, you need to use the accessor methods of PFObject to get at the colors (or array of colors).
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.