In my objective-c project, I have a weird, lets say, feature I have a class, like this:
#import <Foundation/Foundation.h>
#interface Convert /* : NSObject */ // <--- is that necessary?
+(int) toInt:(id) obj;
#end
#implementation Convert
+(int) toInt:(id) obj
{
return [obj intValue];
}
#end
What happens is, when I step through the code It works fine, but I get a cryptic error in the console (even though code is completely fine, works as expected):
2010-11-03 09:35:49.422 Tests[14066:5f03] *** NSInvocation: warning: object 0x9e424 of class 'Convert' does not implement methodSignatureForSelector: -- trouble ahead
2010-11-03 09:35:49.422 Tests[14066:5f03] *** NSInvocation: warning: object 0x9e424 of class 'Convert' does not implement doesNotRecognizeSelector: -- abort
Yet, even when It says abort, the code still works. However, when I run it without stepping through those lines of code, it aborts. What Is happening and why?
The simple answer is "yes".
Or more specifically, the runtime expects objects to conform to the NSObject protocol, and the simplest way to do this is by making sure your objects inherit from the NSObject class.
Related
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.
I have a header file for an object as follows.
#import <Foundation/Foundation.h>
#interface CSSRuleSet : NSObject{
NSMutableArray *Selectors;
NSArray *Properties;
NSMutableArray *Values;
}
-(void)printElement;
-(void)initialiseArrays;
-(NSString *)getValue:(NSString *)Property;
-(void)assignValue:(NSString *)Property:(NSString *)Value;
-(void)addSelector:(NSString *)Selector;
#end
However, when I try to call methods on that object, some work, others throw up an error "no visible #interface for 'CSSStore' declares the selector 'initialiseArrays'".
The ones I am having problems with are printElement and initialiseArrays. For some reason I couldn't write a custom init function for this object either: it was there and didn't throw up any errors, it just wouldn't run.
Let me know if more information is needed. Thanks in advance!
This class is CSSRuleSet. You appear to be trying to send messages intended for this class to a different class called CSSStore. The most likely reasons would be that either you've lost track of what object you're passing around at some point or you're not managing retains and releases correctly in a non-ARC program.
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 just curious about whether declaring a variable in a way known from Java is possible in Objective-C:
Class<?extends SomeType>
For example: I have a class called MyClass. It has a static method
+ (void)myMethod
It has also two subclasses: MySubclassA and MySubclassB. I have such code:
Class myClass;
if(<some condition>) {
myClass = [MySubclassA class];
} else {
myClass = [MySubclassB class];
}
[myClass myMethod];
This code works fine, there are no compiler warnings, but I am just curious whether the construction I mentioned is somehow present in Objective-C.
Thanks!
Objective-C does not have templates (like C++) or generic types with type erasure (like Java) or runtime generic types (like C#). Unlike these languages, Objective-C messages are dynamically dispatched at runtime (instead of bound at compile time). Thus, many of the systems for producing type-agnostic code in C++, Java or C# are unnecessary. Objective-C prefers "duck-typing" whereby any object that responds to a given selector (message) can be given that message by calling code, regardless of the receiving object's type. Since classes are objects in Objective-C, the same is true for class methods as for instance methods.
So, given
#interface MyClassA : NSObject
{}
- (void)someMethod;
#end
#interface MyClassB: NSObject
{}
- (void)someMethod;
#end
calling code can look like this
- (void)someOtherMethodInAnOtherClassWithObject:(id)obj
{
[obj someMethod];
}
This code will compile and will work fine at runtime, assuming obj is either an instance of MyClassA or MyClassB.
Of course, good practice would dictate that you define a #protocol in this situation:
#protocol MyProtocol
- (void)myMethod
#end
and declare that your MyClassA and MyClassB both implement the MyProtocol protocol. Your calling code would then look like
- (void)someOtherMethodInAnOtherClassWithObject:(id<MyProtocol>)obj
{
[obj someMethod];
}
and the compiler would give you a warning/error (depending on -W flags) if you tried to call someOtherMethodInAnOtherClassWithObject:, passing an object of a type that doesn't implement the MyProtocol interface.
Note that id<MyProtocol> is not a generic type, it's an instance of type id that you are claiming implements the MyProtocol protocol. Also note that the first version of client code works just fine because all that really maters is whether obj can respond to the -myMethod selector.
Is it possible to declare a method as private in Objective-C?
If you're working in Objective-C 2.0, the best way to create methods that are "hard" for others to call is to put them in a class extension. Assuming you have
#interface MyClass : NSObject {
}
- (id)aPublicMethod;
#end
in a MyClass.h file, you can add to your MyClass.m the following:
#interface MyClass () //note the empty category name
- (id)aPrivateMethod;
#end
#implementation MyClass
- (id)aPublicMethod {...}
- (id)aPrivateMethod {...} //extension method implemented in class implementation block
#end
The advanage of a class extension is that the "extension" methods are implemented in the original class body. Thus, you don't have to worry about which #implementation block a method implementation is in and the compiler will give a warning if the extension method is not implemented in the class' #implementation.
As others have pointed out, the Objective-C runtime will not enforce the privateness of your methods (and its not too hard to find out what those methods are using class dump, even without the source code), but the compiler will generate a warning if someone tries to call them. In general, the ObjC community takes a "I told you not to call this method [by putting it in a private class extension or category or just by documenting that the method is private] and you called it anyways. Whatever mess ensues is your fault. Don't be stupid." attitude to this issue.
No, any object can send any message to any other object. You can, however, put the method in a category that's part of the class's implementation file. That way, you'll get a "Class may not implement this method" warning if you try to call it anywhere else. That's the normal way of making a method "private."
There is nothing that will prevent the method being called (since objective-c is message based anything can be sent any message), but you can declare them outside of the header so they are not visible and the compiler will generate warnings if used.
This works for both class and instance methods.
E.g.
#import "SomeClass.h"
// Interface for hidden methods
#interface SomeClass (hidden)
+(void) hiddenClassMethod;
-(void) hiddenInstanceMethod;
#end
Note: Do NOT declare variables like this or they will become class-variables - e.g. only one variable will be used by all instances.
You can do so by using categories. I've got a fuller description in my answer to this SO question.
As has been said, you can't stop anyone sending a message to a selector, but by using categories you can reduce the visibility of these functions.
Also, you can have more than one category extending a class. So, by using informative category names you can group private functions into related blocks, improving the self-documenting nature of your code.
As others mentioned, you can't have code that's
a method, and
impossible to call from outside a class.
Folks have already pointed out that you can abandon point 2, and get a method that's hard-but-not-impossible to call. Alternatively, why not abandon point 1?
static id myPrivateMethod(MyObject *me, int arg1, id arg2) { ... }
Now the code can only be called from within same file. You don't get any of the magic private-member access you can get with a method, so this is by no means a perfect solution. But there's no better way to achieve privacy.
To implement hidden methods (instance and/or class)
// ===========================
// = File: SomeClass.m
// ===========================
#import "SomeClass.h"
// =================================
// = Interface for hidden methods
// =================================
#interface SomeClass (hidden)
-(void) hiddenInstanceMethod;
#end
// ================================
// = Implementation for SomeClass
// ================================
#implementation SomeClass
-(void) hiddenInstanceMethod
{
printf( "Hidden instance method\n" );
}
-(void) msg
{
printf("Inside msg()...\n");
[self hiddenInstanceMethod];//private method calling
}
#end
http://macdevelopertips.com/objective-c/private-methods.html
reffer this link it will be helpful .