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.
Related
Hopefully not a ridiculous question as I'm a self taught programmer, but I found some code which looked like it might help me do something I wanted to. Basically I want to enhance the NSLog() function in one of my apps, and would like to call my method in the same way as NSLog(). It's very difficult to google 'void function()' because nothing seems to be relevant, I'm used to methods that are constructed like this:
-(void)RLog(NSString*)statement;
But the sample suggested using:
void RLog(NSString *statement,...);
This seems to work, and lets me call it with 'RLog(#"My message")', however using it this way the method ignores the class variables, and seems I can't use 'self' either ...
Logging.h
#import <UIKit/UIKit.h>
#import Foundation.NSString;
#interface Logging : NSObject
#property (nonatomic) BOOL enabled;
void RLog(NSString *statement,...);
#end
Logging.m
#import "Logging.h"
#implementation Logging
#synthesize enabled;
void RLog(NSString *format,...) {
/* something that uses 'enabled' throws 'Use of undeclared identifier enabled' */
/* something else that uses '[[self class] session]' throws 'Use of undeclared identifier self' */
}
#end
Hopefully I've included enough information to explain my issue, and not removed too much to make it hard to understand!
Thanks in advance.
Plasma
void RLog(NSString *format,...)
... is not an Objective-C method; it's just a C function.
C functions are global and free-standing. There is no self here and no connection with Logging's enabled. As far as this function is concerned, the Logging class might as well not exist at all.
After a bit more investigation I found a way around this using the information here.
I added a class variable called thisClass and then assigned 'self' to it during my class init stage.
#implementation Logging
id thisClass;
- (id) init
{
if (self = [super init])
{
thisClass = self;
}
return self;
}
From inside the C function I can now call methods in my Logging class using:
[thisClass log:#"Testing"];
Without having to send "self" in as a parameter, I've moved the rest of the code which needs the local variables in to my 'log' method and simply use the C method to call it in a simplified way.
Plasma
I am testing some simple Objective-C code on Windows (cygwin, gcc). This code already works in Xcode on Mac. I would like to convert my objects to not subclass NSObject (or anything else, lol). Is this possible, and how?
What I have so far:
// MyObject.h
#interface MyObject
- (void)myMethod:(int) param;
#end
and
// MyObject.m
#include "MyObject.h"
#interface MyObject()
{ // this line is a syntax error, why?
int _field;
}
#end
#implementation MyObject
- (id)init {
// what goes in here?
return self;
}
- (void)myMethod:(int) param {
_field = param;
}
#end
What happens when I try compiling it:
gcc -o test MyObject.m -lobjc
MyObject.m:4:1: error: expected identifier or ‘(’ before ‘{’ token
MyObject.m: In function ‘-[MyObject myMethod:]’:
MyObject.m:17:3: error: ‘_field’ undeclared (first use in this function)
EDIT My compiler is cygwin's gcc, also has cygwin gcc-objc package:
gcc --version
gcc (GCC) 4.7.3
I have tried looking for this online and in a couple of Objective-C tutorials, but every example of a class I have found inherits from NSObject. Is it really impossible to write Objective-C without Cocoa or some kind of Cocoa replacement that provides NSObject?
(Yes, I know about GNUstep. I would really rather avoid that if possible...)
EDIT This works:
// MyObject.h
#interface MyObject
#end
// MyObject.m
#include "MyObject.h"
#implementation MyObject
#end
Not very useful though...
It's possible to make classes without a base class. There are a couple of things going on. First, your compiler doesn't seem to like the "()" class extension syntax. Other compilers would be OK with it. If you remove those "()" on line four of MyObject.m then your compiler will complain that you've got two duplicate interfaces for the MyObject class. For the purpose of your test you should move that _field variable into the declaration of MyObject in the header file, like:
#interface MyObject {
int _field;
}
-(void)myMethod:(int)param;
#end
Then you can completely remove that extra #interface in the .m file. That should get you started at least.
It's possible, but note that NSObject implements the memory allocation API in objective-c, and if you don't implement NSObject's +alloc and -dealloc or equivalent on a root class, you'll still need to implement the same functionality for every class.
my first question on stackoverflow so please be gentle. I've tried searching for answers but I really need help with this.
The issue is with learning about delegates from Neal Goldstein's Objective-C for Dummies
He has the following in Transaction.h
#import <Cocoa/Cocoa.h>
#class Budget;
#interface Transaction : NSObject {
Budget *budget;
double amount;
NSString *name;
id delegate;
}
//some init method
#end
#protocol TransactionDelegate
#required
- (void) spend: (Transaction *) aTransaction;
//additional optional method
#end
--
//and then in Transaction.m he has this
#import "Transaction.h"
#import "Budget.h"
#implementation Transaction
#synthesize budget, delegate , amount;
- (void) spend {
if ([delegate respondsToSelector:#selector(spend:)])
[delegate spend:self];
}
- (id) initWithAmount: (double) theAmount forBudget: (Budget*) aBudget {
if (self = [super init]) {
budget = aBudget;
[budget retain];
amount = theAmount;
}
return self;
}
- (void) dealloc {
[budget release];
[super dealloc];
}
#end
I have problem understanding the spend method in the Transaction.m file
Can the id type instance variable call ANY method in the class that contains it?
I understand that respondsToSelector is a NSObject method that tells the compiler if a method has been implemented. But how can delegate which is of id-type call that method? the compiler does not even know what object it is yet...
Please help!
P.S. if anybody has any recommendations on good Objective-C books, I'd highly appreciate it. I wanna get into iPhone development but I figured I need to get a good grasp on the basics of Objective-C first.
Thanks!
Yes, you can send any message to the delegate variable, because its type is id.
You wrote this:
[delegate spend:self];
The compiler turns that into a call to the objc_msgSend function, like this:
objc_msgSend(delegate, #selector(spend:), self);
At runtime, the objc_msgSend function searches the method table of delegate's class (and its superclasses) for a method associated with the selector spend:.
Incidentally, we usually declare the delegate variable like this:
id<TransactionDelegate> delegate;
This informs the compiler that delegate will be an object that conforms to the TransactionDelegate protocol. This declaration will help Xcode give you better autocompletion when you're trying to send a message to delegate. If you declare your delegate setter method or property this way, the compiler will also check at compile time that you're setting it to an object that conforms to the protocol.
Good question. Gets at one of the key differences between Obj-C and other compiled languages.
You may send any message to any Objective-C object you like. The message send will try to be resolved by the library called the runtime library and this happens at runtime. At compile time, if you have an object type other than the generic id some IDEs may flag it as a likely user mistake.
At runtime, the runtime library will look for a matching method and then would look whether the class has a fallback handler that wants it and as a last resort would throw an exception. The user code could very well catch this exception and treat it as a normal situation.
Below is a simple PerformSelector that sends a message to obj to perform the looping method. All works well but I get the following yellow warning.
PerformSelector may cause a leak because its selector is unknown.
#import "MyClass.h"
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
MyClass *obj = [[MyClass alloc]init];
SEL mySel = #selector(looping);
[obj performSelector:mySel];
}
return 0;
}
This warning does not make sense because the performSelector must be aware of mySel because the looping method does get called - any ideas whats going on ??
Update
MyClass.h
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
-(void)looping;
#end
MyClass.m
#import "MyClass.h"
#implementation MyClass
-(void)looping{
NSLog(#"Hey, i'm looping");
}
#end
Update -- The Real Answer
This is ARC specific:
performSelector may cause a leak because its selector is unknown
In short, ARC uses information based on the naming conventions and any additional attributes bound to the selector. When accessing a selector by name and performing it via the performSelector: family of methods, that information is lost and the compiler is warning you that it must make some assumptions regarding reference counting because this information is stripped away.
In short, the specific program you posted is safe but you are encouraged to use an alternative which is ARC-friendly.
The Previous Response
A selector's declaration does not need to be visible to the current translation in order to call it.
The compiler is allowed to assume default types for parameters and return types for class and instance methods (id is the default).
There are several compiler warnings which can warn you of these shady actions.
You probably forgot to declare the selector looping in the #interface, or you may have omitted the colon, if it has arguments: looping: would be its name.
this warning is due to that u have not told the compiler where the selector resides, import the file where it is or add the selector to header file where it should be
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];