Unrecongized Selector sent to Instance - objective-c

Ive been through similar questions on here, but can't seem to relate it to my app!
My problem is when i run the program i get at error message
[UIView setAttString:]: unrecognised selector sent to instance 0x7538c60
Ive debugged the code down to 3 lines in the ViewController class - these are:
NSString *path = [[NSBundle mainBundle] pathForResource:#"g1" ofType:#"txt"];
NSAttributedString* text = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
[(CTView*)self.view setAttString: text];
Im pretty sure its with the final line, but as this line has been lifted from an example app I haven't really grasped the proper understanding of what it does, and therefore can't see anything wrong with it! Any obvious or common errors I could try to resolve? I don't know how much of my code is needed for the clever folk out there to help me out - let me know and I can add more snippets!
Thanks in advance!

In human terms, that snippet is loading a string from your app's resource file, then sending it to the object referenced by self.view by means of the setAttrString: message.
The error you're seeing shows up when an object receives a message that it doesn't recognize. I don't know what a CTView is, but you should ensure that:
The CTView class does actually have a method called setAttrString:
The object referenced by self.view is actually an instance of CTView.
You can verify that latter with the following:
BOOL isCorrectClass = [self.view isMemberOfClass:[CTView class]];
...or just look at it in the debugger at runtime.

Looks like CTView response to setAttString, but your self.view is a UIView instead of CTView. And usually the self.view of a viewController is just a UIView.
If you created the view as an outlet in your IB, make sure you set it to be CTView class.
Or share where did you alloc inited the "self.view" in your last line of code.

Related

Cocoa Outlets acting wierd, won't recognize selector

I'm getting some weird behavior, I Set a Label in Interface Builder, then I connect the label to a file as an Referencing Outlet.
#property (weak) IBOutlet NSTextField *TitleLabel;
When I access that label in the file (cell.TitleLabel.stringValue = title) and run the application, it doesn't recognize it.I get this:
-[NSApplication TitleLabel]: unrecognized selector sent to instance 0x608000101680
The weird thing is that it doesn't always do this, sometimes it works and displays correctly, other times it doesn't.
I've just started messing with IB so I'm probably missing something. Any help?
Is the property really on your NSApplication subclass? or is it on you application delegate class? It's not impossible for it to be on the application object, but it would be a pretty uncommon (and arguably ill-advised) pattern.
In short, I suspect you're probably connecting it to the wrong object.
EDIT: Ah. I see. You're trying to access things via the topLevelObjects array, but in practice, you can't count on the order of topLevelObjects. What you need to rely on the owner's outlets getting populated, but you're passing nil for the owner. topLevelObjects only exists to give the caller "ownership" (in the reference counting sense) of the top level objects in the xib for memory-mangement purposes, it's not really meant to be "used" directly like you're doing here. (In fairness, I can imagine situations where you might need to introspect that array, but this hardly rises to that level.)
The canonical way to do this would be to use an NSViewController subclass as the owner. In Xcode, if you add a subclass of NSViewController to your project, it will give you the option to create a xib file at the same time that will have everything hooked up. Then you just initialize the NSViewController subclass at runtime and the view outlet property of that class will be filled with the root view. You can obviously add more outlets and plug in whatever you like.
This post appears to cover the basics, if your looking for more details. Apple's docs on xib files and how they work are here.
The problem was that the View would sometimes get assigned to NSApplication. I'm not sure if the way that I am initiating the view is the common way of doing it but the problem was within this block of code:
NSArray * views;
[[NSBundle mainBundle] loadNibNamed:#"CollapseClickViewController" owner:nil topLevelObjects:&views];
CollapseClickCell * cell = [[CollapseClickCell alloc] initWithFrame:CGRectMake(0,0,320,50)];
cell = [views objectAtIndex:0];
the problem was that [views objectAtIndex:0] would sometimes return NSApplication. To fix it I just checked the class against itself and returned that object via:
-(CollapseClickCell*)assignCell:(CollapseClickCell*)cell withArray:(NSArray*)array{
for ( int i = 0; i< [array count]; i++) {
if ([[array objectAtIndex:i] class] == [CollapseClickCell class]) {
return [array objectAtIndex:i];
}
}
return nil;
}
I then assign that to the object:
cell = [cell assignCell:cell withArray:views];
It may not be the conventional way of doing it but it works. If there is a better technique or a more common approach please enlighten me! :)

how to call a method from a class in another class

I'm working to a new app for mac osx where i'm using a drag and drop system to let the user to input some files [this part works well] and i have a tabelView where i would like to display the paths of files inputed.
I have the next method in tabelViewController.m:
-(void)add{
NSLog(#"da");
[list addObject:[[Source alloc] init]];
[tableView reloadData];
}
In the DropView.m i included the tabelViewController.h and i'm trying to call the add method but it does nothing:
#import "TableViewController.h"
.....
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender{
[self setNeedsDisplay:YES];
TableViewController *tvc;
[tvc add];
}
Can someone to figure out why it doesn't do anything ?
Edit1:
Ok after I fallow the answers, my concludeDragOperation method looks like this:
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender{
[self setNeedsDisplay:YES];
TableViewController *tvc = [[TableViewController alloc] init];
[tvc add];
[tvc rD];
}
rD is a method from tableViewController which contain the reloadData method.
But it doesn't want to work it don't reload the table view.
Any ideea ???
tvc needs to point to an actual object. [[tvc alloc] init]
Otherwise you are simply calling add on nil. This doesn't cause your program to crash as you might expect in other languages. Try it out and see what happens.
it seems as if you missed a great chunk regarding how OOP and Objective-C work (seriously, no offense there).
What link is there between DropView.m and tableViewController.h do you have?
By typing TableViewController *tvc; all you are doing is creating a pointer. You are neither creating an object nor pointing to an object, you have just simply created a pointer that can eventually point to an object in memory of type tableViewController.
Solution:
What you will need to do, is to somehow create a link between the two classes. For instance, you could create a custom delegate method for DropView that could communicate with any class who uses that custom DropViewDelegate methods. So, you could create a delegate method that tells objects that follow that delegate protocol that you just concluded a drag operation. A tutorial how to do so can be found at my blog [it's a permalink].
I am happy to post code, or you can read it on my blog. Good Luck.

Passing a reference and copying the object from another controller. Objects keep disappearing

I know this is a relativly easy question, but I just can't figure out how to solve this problem:
One of my views will receive a dragOperation and the performDragOperation method should pass the NSURL to my AppDelegate which puts it in an mutArray...
The problem is, that I pass over a reference and the object disappears the moment performDragOperation is done. So I tried several things:
in performDragOperation:
//Puts the reference itself in the folderPaths Array
AppDelegate *appDelegate = [NSApp delegate];
[[appDelegate folderPaths] addObject:referenceTotheNSURLObject];
/* tried creating a NSString and putting it in too. Same result because local variables will disappear */
So I created a method in AppDelegate and tried different things:
- (void)addFilePath:(NSURL *)filePath {
NSURL *copyOfURL = [filePath copy];
[[self folderPaths] addObject:copyOfURL];
}
This makes the most sense to me and the only reason I can think about why this doesn't work is, because copyOfURL itself is a pointer and it points to an localObject that will disappear the moment the addFilePath method is finished? But I'm not allowed to use
NSURL copyOfURL = [filePath copy];
I also tried recreating an NSString object again. Same results.
- (void)addFilePath:(NSURL *)filePath {
NSString *pathString = [filePath absoluteString];
[[self folderPaths] addObject:pathString];
}
I know it will be some relatively simply solution but I'm stuck and can't figure it out. Thanks for your time!

Objective-C Declaring object as a totally different class than what I declared

In a method I wrote, I'm declaring an instance of class 'A' and calling a method on it. At run time, when the method runs, my app crashes. It says an unrecognized selector was sent to an instance of class 'B' even though I declared an instance of 'A'. I read somewhere that I may not be managing my memory correctly so it's sending the method to another class, but I'm using ARC so that shouldn't even be a problem. Help would be much appreciated!
The error I'm getting:
2011-08-27 01:25:49.859 Intelligenda[49385:bc03] PVC: <HomeViewController: 0x59359e0>
2011-08-27 01:25:49.945 Intelligenda[49385:bc03] -[HomeViewController addNewClass:]: unrecognized selector sent to instance 0x59359e0
2011-08-27 01:25:49.947 Intelligenda[49385:bc03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[HomeViewController addNewClass:]: unrecognized selector sent to instance 0x59359e0'
and the method that's being called:
-(IBAction)done:(id)sender{
[teacherName resignFirstResponder];
[className resignFirstResponder];
IntelligendaAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
UINavigationController *nav = delegate.navController;
[nav popViewControllerAnimated:YES];
ClassesViewController *classesParentViewController = (ClassesViewController *) nav.topViewController;
ClassIG *theNewClass = [[ClassIG alloc] init];
theNewClass.className = className.text;
theNewClass.teacherName = teacherName.text;
NSIndexPath *indexPath;
theNewClass.subject = [tableView cellForRowAtIndexPath:indexPath].textLabel.text;
// add reminder to array
NSLog(#"PVC: %#", [classesParentViewController description]);
[classesParentViewController addNewClass:theNewClass];
}
Declaring, say, a pointer NSArray* fred does nothing (other than a sprinkling of compile-time warning messages) to assure that fred is an NSArray. It's what you assign to fred that counts. If you assign an NSDateFormatter, then that's what fred is.
Your assumption that the application delegate's navigation controller has a ClassesViewController on top is clearly flawed. It has a HomeViewController on top. Your structure looks like it may be a little complicated, given that you have a button somewhere wired up to an action in some other part of your controller classes, so there could be a bunch of causative reasons.
First things to check: if you're instantiating buttons programmatically then did you accidentally add the button to the wrong controller? If you're designing everything using the graphical interface designer but keeping it in a single NIB, is it possible you copied and pasted a button and forgot to change what it's wired to?
If you can end up with multiple navigation controllers, are you sure the one held by the application delegate is currently on screen?
the short answer is that typecasting and type conversions are an exercise for the programmer in objc.
read my answer here:
Passing NSNumber* to NSString* expected-parameter does not cause compiler warning / error
...for some more information as to how declaring/casting a variable of an object differs from other languages, and how you can detect those cases.

strange run time error message from CIImage initWithContentsOfURL

When executing the following code I receive a run time error when the code executes the second line of code. The error (which shows up in the debugger) says: [NSButton initWithContentsOfURL:]: unrecognized selector sent to instance 0x100418e10. I don't understand this message, because it looks to me (based on my source code) like the initWithContentsOfURL message is being sent to the myImage instance (of the CIImage class) ... not NSButton. Any idea what is going on?
If it matters ... this code is in the Application Controller class module of an Xcode project (a Cocoa application) -- within a method that is called when I click on a button on the application window. There is only the one button on the window ...
// Step1: Load the JPG file into CIImage
NSURL *myURL = [NSURL fileURLWithPath:#"/Users/Adam/Documents/Images/image7.jpg"];
CIImage *myImage = [myImage initWithContentsOfURL: myURL];
if (myImage = Nil) {
NSLog(#"Creating myImage failed");
return;
}
else {
NSLog(#"Created myImage successfully");
}
This line
if (myImage = Nil) {...
Does assignment instead of comparison
Also, don't put a space before parameter for your method in question. And it should be something like this:
CIImage *myImage = [[CIImage alloc] initWithContentsOfURL:myURL];
CIImage *myImage = [myImage initWithContentsOfURL: myURL];
You have not initialized the myImage variable, but you are sending its value an initWithContentsOfURL: message. When, by chance, it contains the pointer to an existing object (such as existing NSButton object), the exception in your question occurs.
If you are really unlucky, the object you end up sending the message to will respond to initWithContentsOfURL:, in which case this will re-initialize this object with a different URL. Depending on the URL, it may make the object have the wrong contents, or release itself. Either way, it will probably cause several leaks, and will cause a crash, either by sending later CIImage messages to an object that is still not a CIImage (simply a re-initialized other object), or by sending messages to an object that released itself and so is now dead.
The solution is, as Eimantas stated, to allocate a new CIImage object (by sending the CIImage class an alloc message), then send the initWithContentsOfURL: message to that object, then assign that result to the variable.
if (myImage = Nil) {
As Eimantas noted, this is an assignment, not a comparison. Yes, it is perfectly valid to assign to a variable within a condition in C (and so in Objective-C). The compiler offers a warning for this; you should turn it and a bunch of others on. The solution is to use the equality operator, ==.
Furthermore, as Wevah noted, Nil is the wrong constant to use here, since you are comparing an object's pointer to it, not a class's pointer. The correct constant is nil.