Pass anything except sender in IBAction? - iphone

In my view controller (viewDidLoad) I am populating an array defined in the view controllers header file with settings data (from an archive). I am using data from the array to write labels on buttons in the view, no problem so far.
I would like to pass one element of the array through an IBAction to add to the new view controller. I keep getting an error from within the IBAction
'NSInvalidArgumentException', reason: '-[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x5d230f0').
Here is the relevant part of my IBAction code:
-(IBAction)pushedTimer:(id)sender {
if (!timerViewController) {
timerViewController = [[TimerViewController alloc] init];
}
[timerViewController setPreset:[[settingsArray objectAtIndex:0] settingLength]];
[[self navigationController] pushViewController:timerViewController animated:YES];
}
I was thinking that since the array is accessible in other methods, it should also work with the IBAction? The error leads me to believe that the IBAction can not determine that the settingsArray is really an array?
Thanks again.

I am not sure but here is what I think for this common problem:
Your array is garbaged already. What this means is that your array is dealloc somewhere in your code (by your over call of release or autorelease) then the string is allocated into the same memory area of the array. So that when the system try to call the object in that memory area, it is calling a NSString object not a NSArray object anymore.
You should double check all the release and autorelease of your array

Do instances in settingArray implement settingLength?
The question was itself a answer. I meant instances should implement settingLength.

How are you defining the settingArray? Are you creating a #property and #synthesizing it? If you're not, then you can't access that in allocated instances of that object, so your array will be nil. Also make sure to check what #alones said!

-[NSCFString objectAtIndex:]: unrecognized selector sent sounds like settingsArray is a NSString, not a NSArray.

Related

Xcode 4.3.3 -[__NSArrayM length]: unrecognized selector sent to instance 0x6b6dc60

I have an iPhone application where i download information from the internet and put it into an NSString. It works fine, until i download large files and put it into that one string, then i get the error
-[__NSArrayM length]: unrecognized selector sent to instance 0x6b6dc60
At one point i was getting a EXC_BAD_ACCESS error, but now that's not showing up. I'm guessing that it is a memory problem but i dont know how to fix it. Is there a limit to how large a string variable can be? Any suggestions? I should also mention that the error sometimes doesn't show up, but most of the time it does. Thanks in advance.
Well, it looks like you're trying to get the length of the array by calling a method called length on an array, but to get the length of an array you use the count method like this for example:
NSInteger numberOfElements = [someArray count];
Hope this helps!
P.S. The length method exists but it is used on NSString objects to get the number of characters in the string.
----UPDATE-----
From Ray Wenderlich's "My App Crashed, Now What?" tutorial:
The error message “unrecognized selector sent to instance XXX” means that the app is trying to call a method that doesn’t exist.
So somewhere in your code, you are calling the length method on an object of type NSArray.
You are actually calling the length method on an object of type NSMutableArray, and you know that from the error because __NSArrayM represents an NSMutableArray object; a regular NSArray object would be represented as __NSArrayI (the suffixed "M" stands for "mutable" while the suffixed "I" stands for "immutable").
I even found a very similar question that has a very similar answer to mine:
NSArrayM length : unrecognized selector sent to instance
Heh, I had this before. Somewhere you're doing this: [array length]; but arrays use "count", not "length".
This is happening because you are trying to cast NSMutableArray to NSString, you can remove this error simply by using objectAtIndex:0.
when we use objectAtIndex:0 ,it returns object and in your case that object is your NSString & hence removes error.
e.g.
self.quizTextView.text=[questionTexts objectAtIndex:0];
Try turning on zombies to get a better error message. It's probably something being deallocated before you expect. You can also try running your app in the "Allocations" or "Leaks" instrument to track down why your objects are being released before you expect.

Modifying original data from detailView?

I'm working on iPhone and I'm using navigation.
I have list of data in RootViewController, and pass one data to detailViewController when a cell is clicked. Like this,
detailViewController.message = [tableData objectAtIndex:indexPath.row];
And I want to modify the content of 'message' in detailViewController. Is that possible?
I've tried that, but I get an error that it's immutable object. How can I do that? Somebody give me a hint. Thanks ;)
Added ------------------------------------------------
Ok. I'll specify the question.
in detailViewController, the message is decleared NSMutableDictionary* type.
and used like this.
NSMutableString *str = [m_message objectForKey:KEY_CONTENT];
[str appendFormat:#"appended!"];
And I've got this message.
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendFormat:'
Can't I just modify it's content like modifying data in c++ using pointer?
I think it would be best to use a delegate pattern for this. Create a DetailViewControllerDelegate protocol that informs its delegate of a changed message. Something along the lines of:
-(void)detailViewController:(DetailViewController *)controller didChangeMessage:(NSString *)message;
You could also directly manipulate the object by using a mutable one (NSMutableString, NSMutableArray etc.), but using a delegate improves reusability and decouples your classes.
EDIT:
The fact that your dictionary is mutable doesn't mean the object inside it are mutable as well. Your string str is probably immutable. Since NSMutableString is a subclass of NSString, the assignment will work though. You should make sure that you put a mutable string in the dictionary, or use the mutableCopy method of NSString to get a mutable copy of it.
It depends on what type of object you are passing. Immutable means that you cant alter the object. If you for exaple use NSArray, you have to switch to NSMutableArray instead. The same for string or dictionary.
Okay, i think i figured it out. The documentation for appendFormat says that appendFormat is for appending objects, just like when you use stringWithFormat.
The documentation states that:
The appended string is formed using
NSString's stringWithFormat: method
with the arguments listed.
You should use appendString to get the result you want.

I have to retain a NSMutableArray although it's a property

I'm new, but I read a lot about memory management, and really tried to find the answer myself.
It sounds so basic and yet I apparently don't get it.
I have a NSMutableArray as property in .h:
#property (nonatomic, retain) NSMutableArray *documentListArray;
I synthesize it and release it in (void) dealloc.
To populate the array, I have a method - (void)updateRecordList and in there:
self.documentListArray=[DocumentDatabase getDocumentListSortedByDate];
EDIT:next line:
[[self recordListTableView] reloadData];
where DocumentDatabase is a different class with the class methods getDocumentListSortedByDate and getDocumentList.
Here is what is happening in getDocumentListSortedByDate:
NSMutableArray *returnArray = [DocumentDatabase getDocumentList];
//sorting...
NSLog("array count:%i",[returnArray count]); //returns correct numbers first and second time
return returnArray;
and in getDocumentList
NSMutableArray *returnArray = [NSMutableArray arrayWithCapacity:files.count];
//add file data to array...
return returnArray;
This works the first time I call updateRecordList, but after adding a file and calling updateRecordList a second time, it crashes with (using NSZombies):
* -[NSCFNumber dealloc]: message sent to deallocated instance 0x7504c90.
With a lot of logging I narrowed the problem down to the line above in updateRecordList and it works if I change it to:
self.documentListArray=[[DocumentDatabase getDocumentListSortedByDate] retain];
My conclusion is that the array down in getDocumentList has been autoreleased before it arrives. So my questions are:
1. Why do I have to retain it there? Shouldn't that happen by itself by declaring the property (retain)?
Or, in other words, why is the array autoreleased too early (assuming this is what is happening)?
2. When I assign a new array to self.documentListArray, is the old array automatically released? If I try to release it myself before getting a new documentList, it crashes too.
Thanks in advance for any reply.
EDIT:
Maybe I'm an idiot: I failed to mention that documentListArray is the data source for an UITableView (see the added line on top). I suspect that I am doing something wrong with populating the table view, and the array gets retained...? It does however crash on assigning the property, not on reloadData.
I go back to study if I use the UITableViewDataSource protocol properly. Thanks to everybody, your answers brought me hopefully on the right track. Will update when solved.
EDIT2:
It works now without retaining, and I think I understand why: I debugged extensively and found that Objects contained in Objects added to the array where nil. Particularly, deep down in encodeWithCoder I did not use "self" when assigning values. When decoding, those values where nil. Since I changed that, it seems to work.
I suspect that not assigning the new array caused the crash, but the TableView which would read the new array-even before I call reloadData. Which would lead back to Davids question of synchroneous access. Thank you all for your help.
The code you've shown it appears correct; it should not be necessary (or correct) to call retain yourself, as long as you are assigning the value to a property with retain semantics before the autorelease pool is drained. Are all the calls (getDocumentListSortedByDate, getDocumentList) happening synchronously, or are you doing any of this in the background? Double-check that you're assigning using the "self." ("self.documentListArray =") instead of just assigning directly to the instance var ("documentListArray ="); if you omit the "self.", the setter is bypassed.
No, don't free the old value before assigning; that's the setter's job.

unrecognized selector AGAIN

There are LOTS of iphone-related questions of this type. I know; I read them until I wasn't learning anything new, all in an effort to avoid (a) posting and (b) looking mighty green.
#interface CommonCostingClass : NSObject {
}
-(void) theCCC;
#end
That's the whole thing. As minimal as I could make it. I've even resorted to UIView instead of NSObject. Inside CommonCostingClass.m I have
#import "CommonCostingClass.h"
#implementation CommonCostingClass
-(void) theCCC {
// blah-blah
}
Again, that's all of it. Inside myViewController I coded
#import "CommonCostingClass.h"
- (BOOL) textFieldShouldReturn:(UITextField *)textField {
if (textField.tag == 4) {
[(CommonCostingClass *) self.view theCCC]; // <-ka-boom
}
// other stuff
}
The presence / absence of the cast makes no difference.
self.view generates
* -[UIView theCCC]: unrecognized selector sent to instance 0x5d3dd20
2010-07-20 11:30:54.732 Wind17[3233:207]
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[UIView theCCC]: unrecognized selector sent to instance 0x5d3dd20'
self generates the same message, with the substitution of "myViewController" for "UIView."
Clean all targets has no effect.
I know that neither UIView nor myView Controller "see" method "theCCC".
I don't know how to say, "It's there! It's there!"
Thank you for the help. Someday this situation will be funny and not embarrassing.
following the comments, on this line
[(CommonCostingClass *) self.view theCCC];
you are trying to perform -theCCC method on self.view. self.view is a UIView.
If you want your custom class to be a NSObject subclass as you have it now, you need to create and initialize a CommonCostingClass object in your view controller, then call -theCCC on it.
edit for unrecognized selector: Unrecognized selector means you are calling a method on a class that does not implement that method. In your case you are calling theCCC on UIView which does not implement or know of a theCCC method.
Seems like you really want
+(void) theCCC;
(note the "+") which is a class method, then you would just call
[CommonCostingClass theCCC]
There really is no mystery to "unrecognized selector" It means the first thing in the brackets (in your case self.view) does not understand (have the method) theCC. And why would it?
You have declared a type of class, but in order to make use of that class you have to have an instance somewhere. So how did you think an instance of CommonCostingClass was ever created?
At least two problems here
If you are going to use CommonCostingClass as a view, it needs to subclass UIView. In the code you're posting, CommonCostingClass is a subclass of NSObject. That could be a typo or it could indicate a much more fundamental issue with what you're trying to do here.
You need to make sure the that view property of your UIViewController is set to be an instance of CommonCostingClass. The easiest way to do this is using Interface Builder.

Cocoa touch - problem with button-viewController connection

I'm very new to cocoa touch and am stuck on a problem that doesn't seem to have a google solution. I have added a view to my application, and this view has a button on it. When the button is pressed I want the callback to perform an operation.
My problem is that the callback isn't being called. I created the view in Interface Builder, connected the touch-up-inside connection to my Owner class (in this case a viewController class), and selected the appropriate callback.
The error I get is as follows:
2009-10-13 17:13:51.708 MyApp[7467:20b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSCFSet contactsButtonPressed:]: unrecognized selector sent to instance 0x4c27330'
As I understand it this suggests that the connection between contactsButtonPressed and MyViewController is wrong. I'm not sure where the NSCFSet object comes from.
Does anyone have any idea?
Thanks!
The error I get is as follows:
2009-10-13 17:13:51.708 MyApp[7467:20b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSCFSet contactsButtonPressed:]: unrecognized selector sent to instance 0x4c27330'
You're probably under-retaining whatever controller object of yours is supposed to receive that action message. Add an NSLog call in the controller's dealloc method; you'll probably find that it gets deallocked before you expect it to.
The question to ask then is what should own that controller. Then, make sure that all of the owners are retaining it.
If you're holding the controller in a property, make sure that you actually use that property. A common mistake is to write myController = theController, which bypasses the property and assigns directly to the instance variable, instead of self.myController = theController (property access syntax, implicit accessor message) or [self setMyController:theController] (explicit message syntax).
Also, if you've implemented your own accessors for the property (especially setMyController:), make sure your setter releases the old object and retains the new one. Of course, this is assuming you have a reason to implement your own accessor; normally, you should simply #synthesize the property and let the compiler write the accessor for you.
somewhere in your code you have a line that looks like this:
[button addTarget:self action:#selector(contactsButtonPressed:)];
If you have a line that looks like this, you will also need to have a method with this signature:
- (void)contactsButtonPressed:(UIButton *)sender {
...
}
If you look at the error, it seems that you are sending the message to an NSCFSet object instead of the controller. I would check that you are setting delegate to self or the controller.
I'm new to cocoa too,
Maybe you forgot to add the sender parameter to your contactsButtonPressed.
Is your view's class named NSCFSet?
Try pasting some code.