Problem assigning value obtained from [array objectAtIndex:] - objective-c

In my Piano class, I have a property (Keys is another custom class)
#property (nonatomic, retain) Keys *lastPlayed;
In one of my Piano methods, I set the value of lastPlayed using an object from an array of Key objects.
self.lastPlayed = [allKeys objectAtIndex:variable];
The above line of code causes the program to crash.
I've noticed that if I hardcode a specific Key object from the allKeys array, then it works fine. Like so:
self.lastPlayed = keyC;
Interestingly, it doesn't crash if I put the crashing code into a different method.
How can I prevent the crash?
EDIT:
I call this method in the Keys class, where my piano is the delegate
[delegate deliverTagwithNameTag:self.tag]
the piano then responds
- (void) deliverTagwithNameTag:(int)nameTag {
self.lastPlayed = [allKeys objectAtIndex:nameTag];
}

You're probably not getting a plain unexplained crash, you're probably raising an exception. You can watch the console to find out which exception you raised. Normally in this sort of situation it'll be something useful to tell you either that you're asking the array for an out-of-bounds value (which could happen if variable were collecting an incorrect value somehow), that the array itself is invalid (which could be a memory allocation problem) or that the thing returned can't be stored as lastPlayed (which would normally indicate you're doing something custom in the setter and getting an unexpected type of class).
So to prevent the crash, check your console and look for one of those problems.

Related

ARC deallocate my NSmutablearray before NSTableview reloaddata

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

How is type safety possible for an object pointer of id?

I have the following class (picked out of a Apple example):
#interface LeTemperatureAlarmService : NSObject <CBPeripheralDelegate>
#property (readonly) CBPeripheral *servicePeripheral;
#end
and in a different class's method I use the following code:
NSMutableArray *connectedServices = [[NSMutableArray alloc] init];
... // Adding some myService objects to connectedServices
for (id service in connectedServices) {
if ([service servicePeripheral] == parameter) {
...
}
}
Now the thing which drives me crazy is the part where I can send servicePeripheral to service.
As far as I understand how id works, it's basically a pointer which can be literally point to any object. My NSMutableArray is an untyped array which can hold any type of object in it, even mixed, so I don't have to be careful what I put in.
So how can it be that I can use [service servicePeripheral] even though I never specified the type of service? And how does Xcode know that and even suggest that method in code completion?
Objective-C works different in the respect of method invocation than say C++. The compiler doesn't have to know, because it's not done at compile time, methods are invoked at runtime. Specifically, methods are send to objects, instead of called on them. You send the servicePeripheral method to the object and the runtime takes care of calling the right function. This also makes it possible for you to send methods to nil without crashing (it will return false/0/NULL)
Types in Objective-C are mostly used for compile time safety, which you lose with your approach. The compiler can't warn you that the types don't match, for instance, your array can very well contain NSString instances or anything, and the compiler can't help you there since you tell it that you expect id (aka anything, really) and servicePeripheral is a perfectly valid and known method. You can add type safety by checking the class of the object at runtime using isKindOfClass:, for example like this:
for (id service in connectedServices) {
if ([service isKindOfClass:[LeTemperatureAlarmService class]] && [service servicePeripheral] == parameter) {
...
}
}
So how can it be that I can use [service servicePeripheral] even though I never specified the type of service?
It is exactly because you declared service as an id. This tells the compiler to turn off all static type-checking and permit you to send any message to service. That is what id is: it is the universal recipient (any message can be sent to it, any object value can be assigned to it) and the universal donor (it can be assigned to any object variable).
And you are perfectly right to be wary of this, since it can cause you to crash later. It is not (as your question title has it) "type safety". It is type unsafety! The compiler will happily let you say (for example) [service count] (because service is typed as an id), but you will crash later when the app runs, because this object does not respond to the count message.
So don't do that! Use explicit types so the compiler can help you in advance.

Changing value of a NSString

I am having problems changing the value of an NSString.
It is declared in my class like this:
#property (strong, nonatomic)NSMutableString *votes;
When the object is created, it is set like this:
song.votes = [dict objectForKey:#"Votes"];
And finally is where the trouble occurs. Later in my code I try to modify the value like this:
song.votes =[responseArr valueForKey:#"CNT"];
This line is leading to this crash:
'NSInvalidArgumentException', reason: '-[__NSCFString setVotes]:
unrecognized selector sent to instance 0x14f84430'
I'm think my problems is caused by one of these:
1. Incorrectly setting the properties above. I've tried setting it as (copy, nonatomic) as well but it does the same thing.
2. i need to use an NSMutableString for this. I tried changing it to NSMutableString but it still crashes when it changes (admittedly I am initializing and changing it the way way when using NSMutableString, am not entirely sure how to change things when its Mutable.
I think the problem is in the way you're allocating / setting your song object. Somewhere between setting the first and the second value, you're probably deallocating song and then trying to set it's properties, or you're modifying it in such a way that it's not the same class type anymore.
unrecognized selector sent to instance 0x14f84430' pretty much sums it up for you. The second time you try to set the votes property, it tries to access the synthesized setter (setVotes) from song which is no longer the class you think it is.
From the error it looks like you may be re-allocating song as a NSString object. That's why it's trying to access a setVotes method on NSString and such a method does not exist, so it bails out and crashes.
Are you sure you're not doing something like song = [someString retain]; ?
Use -mutableCopy if you need a mutable copy of your NSString.
song.votes = [[dict objectForKey:#"Votes"] mutableCopy];
Assuming responseArr is an array, [responseArr valueForKey:#"CNT"] returns an array with the return value of each of the instances in responseArr. Your property is for a NSMutableString, but you set it to a NSArray.
(Also, do provide the actual error that you get when you crash instead of just saying 'it crashes'.)

NSString unexpectedly becomes __NSCFDictionary

I have this very strange problem, I'm new to objective-c and it probably comes from depths which I don't comprehend yet.
So, in my header file I declare the variable
NSString *curTitle;
then in .m file I synthesize it:
curTitle = [[NSString alloc] init];
after that in other method I assign it:
curTitle = string; // string is an instance of NSString
and at the end of the day when I'm trying to assign
slide.title = curTitle; //slide is a managed object (CoreData)
I'm getting this error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "title"; desired type = NSString; given type = __NSCFDictionary; value = {
}.'
Interesting fact that in iphone SDK 3.2 it worked, but after I installed SDK 4 I have this error
Another interesting fact that if make my curTitle property of my class (with #property and #synthesize) it also works
Any ideas?
Thanks
When an object seems to change class, it's almost always because it has been deallocated, and another object is now residing on the same memory location. All object variables are actually pointers to memory locations (that's what the * means), and unlike in many other languages you have to always remember that you're working with memory locations. (Well, not always, once you get the hang of it. But definitely when you're debugging.)
To debug these problems, it can be very useful to use NSZombie. Just search SO or the web for info.
then in .m file I synthesize it:
curTitle = [[NSString alloc] init];
This is not synthesizing. What you are doing here is merely assigning a value to the variable. More precisely, you create an object somewhere in memory (alloc) and initialize it (init) and then you set the value of curTitle to point to that memory location.
There is no need for you to have this line in your code at all.
curTitle = string;
Here you are overwriting the old value of curTitle with a pointer to another string. Your problem is most likely that that other string later gets deallocated, and the memory location gets reused to hold another object (a dictionary in this case). (If you don't know about the retain/release mechanisms, you need to read up on those to understand what happens.)
slide.title = curTitle;
Since curTitle is pointing to a memory location that has been re-used to hold a random object (or even worse: garbage) this line will fail. In fact, you're lucky that it fails, because if it didn't (if the location hadn't been reused yet) it would be even harder to detect the bug.
What you should do is to declare a property, then synthesize it and access the variable through the property:
self.curTitle = aString;
This will make sure that you actually copy and take ownership of the string so that even if the original string is released, you will still have a valid copy.

Debugging unexpected error message - possible memory management problem?

I am trying to debug an application that is throwing up strange (to my untutored eyed) errors. When I try to simply log the count of an array...
NSLog(#"Array has %i items", [[self startingPlayers] count]);
...I sometimes get an error:
-[NSCFString count]: unrecognized selector sent to instance 0x1002af600
or other times
-[NSConcreteNotification count]: unrecognized selector sent to instance 0x1002af600
I am not sending 'count' to any NSString or NSNotification, and this line of code works fine normally.
A Theory...
Although the error varies, the crash happens at predictable times, immediately after I have run through some other code where I'm thinking I might have a memory management issue. Is it possible that the object reference is still pointing to something that is meant to be destroyed? Sorry if my terms are off, but perhaps it's expecting the array at the address it calls 'count' on, but finds another previous object that shouldn't still be there (eg an NSString)? Would this cause the problem?
If so, what is the most efficient way to debug and find out what is that address? Most of my debugging up until now involves inserting NSLogs, so this would be a good opportunity to learn how to use the debugger.
This is a sign that the memory location at which your code is expecting your array to live has either:
Been deallocated and another variable has been allocated in the same place
Been clobbered by some bad code
My bet would be on the first one. You'll want to carefully look at where you are allocating the array and make sure that you're not allowing its retain count to reach zero.
Remember that if you're allocating the array using a convenience method (basically one that starts with array) and not either retaining it or assigning it using dot notation (e.g. self.myArray = [NSArray arrayWith...]) and a property marked retain, it will be freed possibly as soon as the method in which you allocated it returns.
TL;DR is to check where you're assigning the array and make sure you're using something like this:
self.startingPlayers = [NSArray arrayWithObjects:#"first", #"second", nil];
and not like this:
startingPlayers = [NSArray arrayWithObjects:#"first", #"second", nil];
That one's bitten me countless times, including in the middle of a presentation right after I mentioned not to do it.
What does [self startingPlayers] return? Try printing that first:
NSLog("startingPlayers is %#", self.startingPlayers);
Perhaps startingPlayers contains a bad pointer (uninitialized) or a pointer to something that has already been released (and reused for something else).