setDelegate:self generates a caution flag - objective-c

I am trying to learn Objective C and have an error in the code for one of my lessions and I do not know how to solve it.
Code:
// AppController.m
#import "AppController.h"
#implementation AppController
- (id)init
{
[super init];
speechSynth = [[NSSpeechSynthesizer alloc] initWithVoice:nil];
[speechSynth setDelegate:self];
voiceList = [[NSSpeechSynthesizer availableVoices] retain];
Return self;
}
From [speechSynth setDelegate:self]; I get the error: Sending 'AppController *' to parameter of incompatible type 'id< NSSpeechSynthesizerDelagate>'.
The program compiles with a caution flag and seems to run correctly. I have compared my code with the author's code and can find no differences and none of my searches have indicated I should get an error on this line. The book was written for Xcode 3 and I am using Xcode 4.0.2.
Any suggestions or pointing me in the right direction would be greatly appreciated. Thanks.

Xcode is warning you that the setDelegate method expects an instance of a class that has implemented the NSSpeechSynthesizerDelagate protocol. Now, you have, but you've probably just forgotten to declare that you have. In your class declaration, change
#class AppController : NSObject
to
#class AppController : NSObject<NSSpeechSynthesizerDelegate>
to tell the world "I obey NSSpeechSynthesizerDelegate!", and silence the warning. You never know - you might get warned that you've forgotten to implement some non-optional delegate methods, and save yourself an annoying bug somewhere down the line.

When you cast the self object then warning message disappears.
[speechSynth setDelegate:(id < NSSpeechSynthesizerDelegate >) self];

Related

NSTextField Subclass Crashes on setLineBreakMode: method

I have a subclass of NSTextField and I setting the LineBreakMode.
It works fine under my mac with Yosemite
and Crashes for one of my users on Mavericks
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[XTextField setLineBreakMode:]: unrecognized selector sent to instance 0x7fc784548ad0'
How could I work this round ?
Header File of the subclass
#import <Cocoa/Cocoa.h>
#interface XTextField : NSTextField
- (void)setText:(NSString *)text
#end
Implementation
#import "XTextField.h"
#implementation XTextField
- (void)setText:(NSString *)text
{
if (text)
{
[self setStringValue:text];
}
else
{
[self setStringValue:#""];
}
}
- (instancetype)initWithFrame:(NSrect)frame
{
if(self = [super initWithFrame:frame])
{
[self setEditable:NO];
[self setSelectable:NO];
[self setDrawsBackGround:NO];
[self setBezeled:NO];
}
return self;
}
#end
Calling code:
XTextField* myLabel = [[XTextField alloc]initWithFrame:myFrame];
[myLabel settext:#"text text text"];
[myLabel setLineBreakMode:NSLineBreakByTruncatingTail];
There are lots of questions that need to be answered here. The problem, as indicated by the error message, is that the setLineBreakMode: selector was sent to an object that doesn't recognize that selector. What could be happening that would cause that? Figuring things like this out requires critical thinking and detective work. Here are some ideas.
-setLineBreakMode: does not seem to actually be implemented by NSTextField; it is a method of NSCell, and of NSMutableParagraphStyle, as far as I can tell. If you have an NSTextField (or a subclass of it) you'd normally call [[myTextField cell] setLineBreakMode:...], but your code snippet doesn't indicate that you are doing that. So unless you implemented this method in your subclass – which you don't state that you did – this is probably the reason for the crash. Perhaps you don't see the crash on your Mac because this code path doesn't get hit, for whatever reason? Or perhaps Apple privately implemented this method in Yosemite but not in Mavericks? Who knows. Do you get a warning from the compiler on that line, saying that the object does not respond to that selector? Do not ignore compiler warnings.
The code you posted looks like you are calling setLineBreakMode: on the class object, not on an instance of the class; normally classes start with a capital letter, whereas instances start with a lowercase letter. Obeying coding conventions like this makes things much less confusing for everybody. And if your subclass is really named NSTextFieldSubClass, then I agree with #MichaelDautermann that you should never, ever name classes with an NS prefix; that is both confusing and asking for trouble, since for all you know Apple has a private subclass with exactly that name. Class names beginning with NS are reserved by Apple.
It could be that the object you think is in the variable that you have apparently named NSTextFieldSubClass is not an instance of your subclass at all, or has been freed (and perhaps replaced by a new object at the same address), or some such problem, and that that is why it doesn't respond to the selector. You could investigate this by turning on NSZombieEnabled, examining it in the debugger, adding an NSLog of it (perhaps with an added -description method in your subclass), or many other techniques.
That's all pretty vague, but then the question is vague. You need to post the code for your subclass, the code where you instantiate the subclass, and the code surrounding the line that crashes, at a minimum, to get more specific help. We can't read your mind, and the root of the bug may well be in one of those places.

Release method not recognized at runtime (non Cocoa)

I'm a newbie to Objective-C but have extensive experience in C and C++. The first thing I have noticed is that there is a real void in basic tutorials out there as all assume you are developing for the iPhone or Mac and using Cocoa. I'm not using Cocoa or Gnustep. To the point:
As a simple example to get started I'm trying to wrap the C's File I/O functionality. My code starts as
File.h
#include <objc/Object.h>
#include <stdio.h>
#interface File:Object
{
FILE *pFile;
char *path;
}
#property FILE *pFile;
#property char *path;
- (void)new;
- (void)OpenReadText:(const char*)var1;
- (void)release;
#end
And File.m
#include "File.h"
#implementation File
#synthesize pFile, path;
- (void)new
{
self = [super init];
}
- (void)release
{
fclose(pFile);
[super release];
}
- (void)OpenReadText:(char*)var1
{
path = var1;
pFile = fopen(path,"r");
}
#end
Then main.m
#include <stdio.h>
#import <objc/Object.h>
#include "File.h"
int main(void) {
File *Fileobj = [File new];
[Fileobj OpenReadText:"File.h"];
[Fileobj release];
}
The compiler gives me a warning that my object "may not respond to '-release'". Then when running the program is results in a runtime error: "does not recognize release. This application has requested the Runtime to terminate" .. and so on.
I'm guessing I'm making a simple newbie error, but where? Or perhaps there is something missing? I'm hoping someone can point me in the right direction here. Thanks.
If this qst has been asked already then a reference would do too. I did try to find a reference but no luck.
FOLLOW UP:
changed release method to
- (void)release
{
fclose(pFile);
[super free];
}
and it appeared to work. Apparently free is recognized in object.h.
As others have said it is unusual to use Objective-C without the Foundation frameworks. However, the Object class should implement release, retain etc. The Object class included (but not used) in Apple's Objective-C Runtime certainly contains these basic methods.
Assuming your Object class does contain these basic methods there are a couple of problems with your class as implemented.
First, you have created a new instance method which simply calls [super init]. The new method by convention is a class method which is shorthand for calling alloc and init to create and initialise an object. new is defined in Apple's Object class. It is implemented as:
+ (id)new
{
id newObject = (*_alloc)((Class)self, 0);
Class metaClass = self->isa;
if (class_getVersion(metaClass) > 1)
return [newObject init];
else
return newObject;
}
Note that this method is a class method, signified by the + instead of the -. GNUStep implements new as follows:
+ new
{
return [[self alloc] init];
}
The idiomatic way to use new would be:
File *obj = [File new];
This is in fact what you have done, however, this is calling the class method new not your instance method new.
If you wanted to call your new method you'd have to call:
File *obj = [[File alloc] new];
but as others have stated you'd need to return your object. Removing your new method would have no effect on your implementation as it isn't currently being called.
Secondly, you have placed your call to fclose in your overriden release method. This is wrong, certainly in Apple's implementation of Object anyway, GNUstep appears to be different. release could get called multiple times on a single instance of an object. retain and release are used to increment/decrement the objects retain count. Only when the retain count reaches zero should the file handle be closed. Normally, within Foundation you'd place the call to fclose in a dealloc method. dealloc is Objective-C's destructor method. The dealloc should look something like:
- (void)dealloc
{
fclose(pFile);
[super dealloc];
}
However, dealloc doesn't appear to be implemented in either Apple's or GNUstep's Object class. There is, as you point out in your question a free method which seems to be a destructor.
It would appear that replacing the above dealloc method with an equivalent free method would work as a destructor, e.g.:
- (void)free
{
fclose(pFile);
[super free];
}
Apple's implementation of Object contains retain and release methods but the GNUstep implementation does not. Neither implementation contains a dealloc method.
The implementations of Object.m and NSObject.m for Apple and GNUstep can be found at the following locations:
Apple Object.m: http://opensource.apple.com/source/objc4/objc4-532.2/runtime/Object.m
GNUstep Object.m: https://github.com/gnustep/gnustep-libobjc/blob/master/Object.m
Apple NSObject.mm: http://opensource.apple.com/source/objc4/objc4-532.2/runtime/NSObject.mm
GNUstep NSObject.m: https://github.com/gnustep/gnustep-base/blob/master/Source/NSObject.m
Is release defined on class Object? If it is not, then your call to
[super release];
will not work. (In cocoa, release is a member of NSObject; your Object class may or may not have it, and in fact the retain/release reference counting might not be there at all.)
You should confirm that your base class includes all methods called via super.
As #xlc0212 pointed out, the reference counting style of memory management is included in NSObject.
NSObject is a part of CoreFoundation library for Cocoa, CocoaTouch and GnuStep. I would say you need to link to CoreFoundation.
One book that I've read and focuses on pure Objective-C (not necessarily Cocoa) is "Programming in Objective-C 2.0" by Steven G Kochan.

ios warning calling init method of a uiviewcontroller

I have my custom viewcontroller declared like this:
#interface DetailViewControllerSpeciality2 : UIViewController <UITableViewDelegate, UITableViewDataSource> {
}
and I create a new instance like this:
DetailViewControllerSpeciality2 *detailViewControllerSpeciality = [[DetailViewControllerSpeciality2 alloc] init];
but xcode tell me a warning:
multiple methods named '-init' found
but I don't have declared a -init method...
You aren't showing all the error message, nor the relevant code. Still, there is enough evidence to make an educated guess.
More likely than not, you have an init method declared like:
- (DetailViewControllerSpeciality2 *) init;
The compiler is complaining because that conflicts with NSObject's init (that returns id).
Declare your init to return id and the compiler should be happy. If that isn't the problem, post more code.
try this.
[[DetailViewControllerSpeciality2 alloc] initWithNibName:nil bundle:nil];

Clang generating warning "method '-init' not found" for very simple class

I just came across Clang/LLVM today, and decided to try it out.
My system is FreeBSD8.1-Release.
The default system compiler is GCC4.2.1, which is what I have been using to compile my Objective-C project up until now.
I'm playing around with the Static Analyzer, and would like to know how to eliminate one of the warnings that is being generated.
MyClass.h
#import <objc/Object.h>
#interface MyClass: Object {
}
-(MyClass*) init;
#end
MyClass.m
#import "MyClass.h"
#implementation MyClass
-(MyClass*) init {
self = [super init];
if (self) {
// do stuff
}
return self;
}
#end
The warning:
%clang --analyze MyClass.m
MyClass.m:7:9: warning: method '-init' not found (return type defaults to 'id')
self = [super init];
^~~~~~~~~~~~
1 diagnostic generated.
I take it that the analyzer does not know how to determine super's type (Object, in this case). Is there any way to eliminate this warning (other than by suppression)? I looked into casting super, but it looks like that is not allowed.
Thanks!
Max
Update
Thanks to Dave and bbum for pointing me in the right direction for eliminating the warning. Now I'm trying to figure out why the warning occurs in the first place.
If anyone has any ideas or leads, I love the hear them.
Thanks,
Max
Two issues:
You should be inheriting from NSObject, not Object.
Your init method should return id, not MyClass*.
The warning is saying that it does not know of any method named -init at all in scope at that point. You need to import a header file that declares -init, which is probably Foundation.h or something, depending on what system you're using.

'TileMap' may not respond to '+mapNamed:'

Here's an odd one. I have a class named TileMap with the following interface:
#interface TileMap : NSObject
{
int *data;
int tilesWide;
int tilesHigh;
NSString *imageName;
}
+ (id)mapNamed:(NSString *)filename;
- (id)initWithFile:(NSString *)filename;
#end
The implementation looks like this:
#implementation TileMap
+ (id)mapNamed:(NSString *)filename
{
return [[self alloc] initWithFile:filename];
}
- (id)initWithFile:(NSString *)filename
{
if (self = [super init])
{
// ...
}
return self;
}
#end
But when I add a call to [TileMap mapNamed:#"map.plist"]; to my application Xcode warns:
'TileMap' may not respond to '+mapNamed:'
The application compiles fine and calls to NSLog within TileMap-initWithFile: are logged. I noticed that Xcode's syntax coloring was off for this class and method so I tried renaming both the class and the method separately. The only combination that eliminated the warning and syntax coloring issues was to rename both the class and the method.
Am I colliding with some undocumented framework class or method? Find in Documentation doesn't reveal anything. Find in Project only reveals the call, interface definition and the implementation. I'm stumped (not that it takes much). Is there a way around this without munging my existing naming conventions?
Did you #import the TileMap.h header? Did you save your TileMap.h header?
Turns out my project directory ended up with two TileMap.h and TileMap.m files—visible from the Finder but not in Xcode. One, a complete interface and implementation, in my root project directory. The other just a bare NSObject subclass in my framework subdirectory. Not sure how that happened. Deleting the latter resolved the problem. Thanks for the help just the same Dave.
Shaun,
besides the problem you asked about, you also have a memory leak in +mapNamed:. The following line returns a non-autoreleased object with a retain count of +1, which basically gives ownership to the caller:
return [[self alloc] initWithFile:filename];
According to the Memory Management Programming Guide for Cocoa, you should return autoreleased objects from convenience methods, such as this:
return [[[self alloc] initWithFile:filename] autorelease];
If you have Snow Leopard and Xcode 3.2, you might want to try running the static analyzer to find mistakes such as this one by pressing Cmd+Shift+A.