strange run time error message from CIImage initWithContentsOfURL - objective-c

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.

Related

Unrecongized Selector sent to Instance

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.

Is it necessary to use a temporary variable when setting a properties' value?

I have a (retained) UIImage property that is being used to hold a user selected image.
This is the code I have at present when the user makes a selection:
- (IBAction) selectImage1 {
UIImage *image = [UIImage imageNamed: #"image1-big.png"];
self.bigImage = image;
}
but I'm wondering if it is possible to omit the use of the temporary variable convenience method and just do this:
- (IBAction) selectImage1 {
self.bigImage = [UIImage imageNamed: #"image1-big.png"];
}
If there are problems with this second method (I'm guessing something to do with memory management), could someone please explain?
Thank you!
The second way is perfectly fine. The line UIImage *image = [UIImage imageNamed: #"image1-big.png"]; gives you a variable image that is auto-released. Assigning it to your ivar via the self.bigImage = image calls bigImage's setter method which retains the value. Thus the line self.bigImage = [UIImage imageNamed: #"image1-big.png"]; is equivalent to the more verbose way.
There is no difference in terms of memory management between the two snippets you posted; unless you get really specific about retain counts in between the two lines in the first snippet.
In an ARC environment, the local variable will be a 'strong' pointer, however it is released when the method leaves scope. In the second snippet, there is no intermediate retain/release'd pointer, and so may actually be slightly more efficient.
The places I have seen the first snippet's technique be necessary are when you have a weak pointer (i.e. a weak #property) where setting self.foo = [UIView ... would immediately allow it to be released. In these cases it is better to use a local variable to keep it around while you work with it:
UIView *someFoo = [UIView...
[self addSubview:someFoo];
self.someWeakProperty = someFoo;
compare with:
self.someWeakProperty = [UIView...
[self addSubview:self.someWeakProperty]; // it's already nil!!

Objects not initialized

in objective C, I can do the following
UIImage *myImage = [UIImage imageNamed:#"myPhoto.jpg"];
variable.image = myImage;
and this works just fine. but the object named "myImage" was never initialized, and the UIImage never had any memory allocated and yet the code still works..
Can someone explain what's going on here?
Yes, the object was initialised. The imageNamed: method allocates and initialises an object, sends it an autorelease message, then returns the memory address to you. You store that memory address in the pointer called myImage.
myImage and the object are two different things. myImage merely points at a memory location. It is not the object itself.
You can pass around objects without assigning them to variables, and you can assign one object to many variables.
Consider this:
UIImage *imageOne;
UIImage *imageTwo;
imageOne = [UIImage imageNamed:#"myPhoto.jpg"];
imageTwo = imageOne;
The image wasn't copied. There is only one object in existence. Both variables point to it.
Now consider this:
NSLog(#"%#", [UIImage imageNamed:#"myPhoto.jpg"]);
You didn't assign it to any variable. But the object still existed, right?
Have a look in the documentation for UIImage. Under the heading "Cached Image Loading Routines" and "Creating New Images" are some methods with a + where you might expect a -. This means that calling these methods is the same as calling [[[UIImage alloc] init] autorelease];, though some of them do more (as in custom initialization).
Lots of other Objective C objects have similar methods, for example, NSArray has a method +(id)array that creates and returns an empty array. Your main indicator here is the + instead of the -, but I always check the documentation to check how the initialization is handled and to make sure the object is autoreleased.

Random BAD_ACCESS and "not recognized selector"

Hey, I'm a beginner in Objective C, and my .NET and Java years have rusted my memory management skills, so it's very likely I'm missing something here.
I am building an iPad app. The main view is a SplitView with a TableView on the left, and the detail view contains another TableView. The loading of the latter with data has been commented out in an attempt to single out my problem.
The app seems to work fine (has to fetch data from a .NET WS and parse it into the table), but at random times I receive a BAD_ACCESS or a "selector not recognized" errors.
The selector not recognized error I get here:
-(void) connection:(NSURLConnection *) connection
didReceiveResponse:(NSURLResponse *) response {
[webData setLength: 0];
}
This piece of code I'm sure most of you know about, I got it from all samples I found online and in books to send a web request.
Beats me why it says it does not recognize the setLength selector, webData is defined as
NSMutableData *webData;
Any ideas?
Thanks.
If you do not allocate your webData object either with
NSMutableData* webData = [[NSMutableData alloc] initWithCapacity:2048];
or
NSMutableData* webData = [[NSMutableData data] retain];
then the webData object will most likely be autoreleased during one of the context switches from the NSURLConnection message that you allocated it in (probably connection:didReceiveData:) to the connection:didReceiveResponse: message.
Any object that you do not alloc or explicitly retain is likely to be deallocated during scope changes, even if it is a member variable of your class.
Most likely you aren't creating the NSMutableData correctly. I expect you have code that looks like
webData = [NSMutableData data];
This is going to give you an autoreleased object, and yet you're storing it in an ivar. You need to take ownership of the object when storing it in an ivar. In your case, the simplest way is just to skip the convenience method and go with alloc/init:
webData = [[NSMutableData alloc] init];
For more details, read the Memory Management Programming Guide.
Seems to be very usual (not only beginners) error, when connection is not cancels in dealloc or viewWillDisappear. When you are leaving the controller, you should cancel all connection, timers, etc, created by the controller, to prevent them from calling delegate methods or selectors on deallocated controller objects.
It looks like webData is being deallocated and replaced with some other object. Make sure you retain it if you don't use alloc/init or mutableCopy to get it.

'EXC_BAD_ACCESS' When trying to access a variable?

I get an 'EXC_BAD_ACCESS' error when trying to access variable in a function other than the one it was set in
The variable is set in the 'awakeFromNib' function:
//Retrieve Session-ID
sessionID = [self getSessionID];
And accessed in 'searchBtnClick':
NSLog(#"Commening search (%#)",sessionID); // This causes the error
The variable itself is defined in the header:
NSString *sessionID;
Can someone suggest what might be wrong with that?
The part which of getSessionID which returns the value:
NSString *pC = #"";
// Separate Session ID
pC = [initCookie substringFromIndex:10];
pC = [pC substringToIndex:32];
NSLog(#"Got session ID : %#",pC);
return pC;
Your -getSessionID method is returning an autoreleased variable—when you try to access the pointer again later, the string's already been deallocated and so the reference is no longer valid. You need to call -retain on the variable when you first retrieve it, like this:
sessionID = [[self getSessionID] retain];
Then, later, in your class's -dealloc, you need to balance the retain with a release:
[sessionID release];
If getSessionID follows normal Cocoa conventions, it returns an autoreleased object. You need to retain it, or sessionID will become a dangling pointer as soon as the autorelease pool is drained (probably at the end of the event loop).
If you are new to Objective C and Cocoa, you should make sure to read the Apple documentation about the memory model.
I had similar prob, it crashes when you have not allocated any memory. Releasing it like this:
UIImage *lObj_image = [UIImage imageNamed: #"bluebar.png"];
.
.
.
[lObj_image release];
Check in your viewdidload()