I have a UIViewController that I load every time I click a button:
NearMe * temp = [[NearMe alloc] initWithNibName: #"NearMe" bundle:nil];
I parse some XML with locations and then assign the values to an NSMutableArray, which populates a UITableView.
I parse the XML on the viewDidLoad method, but I don't need to parse it every time, since the value is not going to change. I only want to parse it if the array is nil, so I put the following check in:
if (allLocations == nil) ....
So that the XML is only parsed if necessary, but every time I press the back button (in the UINavigationController) it erases all the objects in the array.... I don't have any idea why this is happening...
Since your app is creating a new NearMe instance each time, the allLocations instance variable will always be nil in viewDidLoad (which, by the way, is only called if the _view instance variable is nil).
If you don't want to recreate the array each time, your app will need to cache it somewhere else. A couple of possibilities would be to store the array in the object that creates the NearMe instance, or to store it in a static variable.
Related
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
I would like, every time this function is called, that the NSMutableArray "sequence" to return the numbers already in the sequence, plus another random one from 0 to 3 at the end. This is the function I have so far:
Edit
I tried calling initialising this function from inside didMoveToView and it now returns a sequence.
This code works now:
-(NSMutableArray *)extendSequence {
int newItem = arc4random_uniform(4);
NSNumber* newItemAsNumber = [NSNumber numberWithInteger:newItem];
[sequence addObject:newItemAsNumber];
NSLog(#"%#", sequence);
return sequence;
}
(I am not sure where/if I could insert the NSMutableArray *sequence = [NSMutableArray alloc] init]]; statement yet, because when I tried earlier, it wiped the sequence each time it was called.)
How could I achieve this?
A random sequence could return to be something like e.g. "1", then "1,3" then "1,3,0" etc.
Thank you in advance.
Sounds like you are a little unclear on where you are keeping track of the "state" of what the sequence is so far. It sounds like you have an instance variable called "sequence" on this object somewhere (otherwise what you are writing now wouldn't compile). This is a reasonable place to keep track of this set of numbers, which will exist throughout the object's lifecycle, but adding to it each time the -sequence method is called.
You should add the initialization line for the array to your object's -init method. That way it is initialized just once with the object.
(The reason the current code returns nil is that you're never initializing the array, so the "additions" to it have no effect. The reason your other version, where you initialize within that method, kept wiping out the contents, is simply that you were creating and returning a fresh array every single time, which would replace the one you'd created the last time.)
I am trying to create a mutable array in objetive c to hold references to objects. The objects in the array are regularly updated through user interaction and i want the array to automatically reflect changes made to the objects as they occur. Does anyone know if there is a way to do this? Perhaps store pointers to the objects instead of the objects themselves in the array? Any help would be much appreciated
Thanks in advance
Edit: I should mention that the objects are not exactly being updated in the strict sense of the word. They are being reinitialized. For ex if i had a controller:
MyController = [MyController alloc] initWith.....]]
the above call is made again with different init parameters.
The array always stores the pointers.... It holds a strong reference to it or sends it a retain message (if using non ARC).
So
[myMutableArray addObject: anObject];
adds the pointer to it.
If you now change anObject's properties and access it later through the array, it will
give you the pointer to just that object with the changes to its properties.
Edit:
No, if you alloc/init, you are creating a new object instance and allocate new memory for it on the heap (ie, it's another pointer to a new memory address).
What exactly are you trying to accomplish? There sure is a way, if you provide a little more detail.
If you alloc/init the object with the same class, why not just create a method to change the object's properties:
Instead of
myObject = [[MyClass alloc] initWithParameter1: one parameter2: two];
You could create a method that changes these properties:
[myObject updateParameter1: anotherOne parameterTwo: anotherTwo];
And, of course, the advantage of a mutable array is, that you can change its contents, so like #Eli Gregory pointed out, you can replace an object with another one (or rather the pointers to it).
Because you want to point to a newly allocated and initialized object, you can't 'update' the pointer, what you can do is 'replace' the pointer with a new one at a certain index.
A method you could use to do this is:
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject
so it would look something like:
NewViewController *new = [[NewViewController alloc] init..];
[myArray replaceObjectAtIndex:x withObject:new];
I've got a UIViewController which has three views: Category -> Sub-Category -> Detail View. The content of the Sub-Category and Detail View depends on which row is clicked in the Category view. This is done with a property called 'categoryClicked' and is declared in the sub-category.m file. It's value is given in the category.m file by the following lines of code.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
Sub-category *sub = [[Sub-category alloc] initWithNibName:#"Sub-category" bundle:nil];
sub.categoryClicked = [_categoryArray objectAtIndex:indexPath.row];
[self.navigationController pushViewController:rubrieken animated:YES];
}
This works perfectly fine until I want to use the value of categoryClicked in the Detail View. In both the category.m and the DetailView.m sub-category.m is imported. For testing purposes I putted a label on the Detail View and in the DetailView.m file I've got the following code:
Sub-category *sub = [[Sub-category alloc] initWithNibName:#"Sub-category" bundle:nil];
label.text = sub.categoryClicked;
I'm convinced this code should do the job but in fact I get an empty label. Is there anybody able to tell me what I'm doing wrong.
Edit
categoryClicked is a property declared in Sub-category.h and synthesized in Sub-category.m.
Wanted to post some more code but there is no more relevant code.
This line...
Sub-category *sub = [[Sub-category alloc] initWithNibName:#"Sub-category" bundle:nil];
...creates a new Sub-category. Since it's new, it doesn't know anything about what information has been given to some other Sub-category object. You need to get a reference to the existing object if you want to access its data.
When you alloc an object, you're allocating memory space for it. Then when you use something with init (like initWithNibName) you're initializing it. So when you allocate memory space for sub and initialize it, you have one object. But then you alloc and init again, which creates an entirely new (and completely unrelated) object. Make sure that you remove anything that could destroy your old object.
Also, the * symbol means that sub is a pointer (it points to a memory location). Whenever you use the assignment operator (=) you're telling it to point to a new thing. What you're doing is telling the label.text pointer to point at what sub is pointing at. But if you change what sub is pointing at and point label.text at the same thing, neither one is pointing at the value you want.
Hope this is clear enough, if it's not trying posting some more code and maybe someone can suggest exact changes.
-EDIT-
If you want to have a reference to an object you can only get it a few ways. What's important to know is that you can't really "create" a reference to an existing object. You have to have some connection to the object.
Declare the object inside of the file you want the reference in with something like Category c = [[Category alloc] init]; Remember this creates a new object, it won't create a reference to an existing object. However, creating the object inside of another object means that one "owns" the other and can do whatever it wants with it (obviously including accessing properties and calling methods).
Use a "chain" of objects to get a reference to your object. So if your file owns a file that owns the object you want you can use topfile.otherfile.objectyouwant. The most obvious example of this is getting a reference to an object owned by a subview.
That's about as basic as it gets; just remember that there aren't any "global" objects that you can just call by name. If your problem isn't solved by this, either look at some sample code and try to figure out how references work, or post another question that's more closely related to your problem
I've always seen that we use an intermediary object, for example, creating an array to fill in another array:
characters = [[NSArray alloc] initWithObjects:#"Antony", #"Artemidorus", #"Brutus", nil];
play.characters = characters;
[characters release];
with characters being an NSArray in the object play.
I saw the same thing with a #property and its self: we did not add the new items directly into this property, just as we don't directly fill in characters in the example above. Is this only about "style"?
This is not a matter of style.
play.characters is a property, and that can "contain" an existing array or nil, but even if it "contains" an existing array, you can't change the contents of an NSArray, so you'll have to create a new one and assign that to the property.
Assigning to a property will, if all was declared well, cause its setter method to run (which could be created by the compiler, if you used #synthesize, or written by you, in code) and that will take care of removing any existing array, assigning the new one and retaining it.
There is actually only one array in play in that little piece of code.
It is not the array that is intermediate, but the variable holding a pointer to it - in this case the variable characters.
This is what happens:
The expression
[[NSArray alloc] initWithObjects:#"Antony", #"Artemidorus", #"Brutus", nil]
allocates an object and initialises it with three NSStrings (which are themselves objects, but let's leave that out for a moment). The initialisation also includes an increment of the retain count, so it is one from the get-go.
This newly created object lives at a given position in memory, say 0100H. This position is then stored in the variable characters. In C terms we say that characters is a pointer to the object.
Then the property #"characters" of the object play is set to point to the same position in memory as the local variable characters. There are therefore now two variables (of which one is also a property) that point to the same object, or, if you prefer, to the same position in memory. If the property is of type retain, this will automatically increment the retain count of the object, so it is now 2.
With the release message in the last line, the object decrements its retain count by one, so at the end of this code snippet, the object is pointed to by the play.characters property, and it has a retain count of one.
To be really clean, this code should probably set the local variable to nil, to avoid confusion between variables holding pointers to the object and the retain count.
All this was meant to show that there really is only one array in play here, but two variables that point to it. So there are not as many computer resources being wasted as it might seem at a first glance.
If you wanted to do it all in a single line, you could write something like this:
play.characters = [[[NSArray alloc] initWithObjects:#"Antony", #"Artemidorus", #"Brutus", nil] autorelease];
but the exact working of this is less clear as it involves one of those mysterious autoreleases, i.e., a release that is handled automatically and postponed to some later stage.
This is a long description, but I hope it sheds some light on what is going on.