Private method declarations in objective-C - objective-c

Do I have to DECLARE all private methods in .m class file inside
#interface ClassName()
//Privare Methods
#end
before
#implementation ClassName
// Implementation of Private & Instance methods
#end
for every method I am implementing & using OTHER THEN the instance methods (methods declared in .h file)?
X-Code 4 DOES NOT give me WARNING for ALL private methods but ONLY for few of them. For example, it warns me for methods I am calling inside gesture handler functions but not inside other routines/methods. I am confused as to declare all non-instance methods or just declare the ones I get warned for.

XCode won't warn about methods that appear before the point of invocation:
#implementation
- (void) foo:(float)x;
{
NSLog(#"%f", x); // prints 15.000000
}
- (void) bar;
{
[self foo:15.0]; // no warning
[self baz:15.0]; // warning
}
- (void) baz:(float)x;
{
NSLog(#"%f", x); // prints 0.000000 instead of 15.0
}
#end
It is strongly recommended to declare methods which you are warned about, the code above gives one example why.

No you don't have to declare every method you implement. The declaration is needed when the method you call is defined after the method which is calling it in .m file:
- (void) methodA {
[self methodB]; //here you will get a warning if you don't define methodB it in a private class extention
}
- (void) methodB {
}

Related

Objective-C hidden static method calling

I google this question and spend some time to figure it out by myself but with a bad luck.
I need to call class's static method which is hidden for class's user.
// MyClass.h
#interface MyClass : NSObject
#end
// MyClass.m
#implementation MyClass
- (NSString *)myInstanceMethod
{
return #"result string";
}
+ (NSString *)myStaticMethod
{
return #"result string";
}
#end
------------------------------------------------------------
// MyCallerClass.m
#import "MyClass.h"
#implementation MyCallerClass
- (void) testMethod
{
MyClass *inst = [MyClass new];
// call 1
NSString *resultInstance = [inst performSelector:#selector(myInstanceMethod)];
// call 2
NSString *resultStaitc = [inst performSelector:#selector(myStaticMethod)];
// call
[MyClass myStaticMethod];
}
#end
Call 1 works good, Call 2 returns nil, Call 3 does not compile.
How can I call static method which does not defined in .h file and give correct returned object?
Thank in advance,
Rost
For Call 2 ,
since it is an class method you should call like
NSString *resultStaitc = [[inst class] performSelector:#selector(myStaticMethod)];
inst is the object.To call a class method you must call with class.
The object instance's class is supposed to be calling the method, not the instance itself.
For call 3
It should be working fine,The result value is never used .the compile error is because
+ (NSString *)myStaticMethod;
not declared in .h
use
NSString *resultStaitc1 =[MyClass myStaticMethod];
and it will return the value to the resultStaitc1
Another option is to declare an informal protocol for MyClass at the top of MyCallerClass.m. An informal protocol is just a category interface without the implementation block. You can stick you method declaration(s) in there. It does raise synchronisation problems between the two source files, but so does performSelector:. Doing it this way lets you call methods that have a different signature to just take [0-2] object arguments and return and object.

is there an equivalent of method declaration/definition separation for Objective-C messages?

Let's say I have an objective-c .m file with the following methods defined:
- (void) doOneThing {
[self doAnotherThing];
}
- (void) doAnotherThing {
[self stillOtherThings];
}
if I compile this, xcode will throw me a warning that the class may not respond to -doAnotherThings, because doAnotherThing is defined below -doOneThing and the compiler doesn't know about -doAnotherThing yet when it's compiling -doOneThing. Of course, the code compiles properly and does in fact work, but I'd like to get rid of that warning message.
The trivial way to solve this problem would be to just define -doAnotherThing before -doOneThing, but sometimes I like to group related methods in the source code in ways that make it hard to re-order. If this were C, I could do something like:
void doAnotherThing();
void doOneThing() {
doAnotherThing();
}
void doAnotherThing() {
...still other things...
}
separating the definition from the declaration. Is there a way to do something like this in objective-c, or otherwise solve my problem?
The typical way to deal with this is as follows:
//in DoThings.h
#interface DoThings : NSObject {
//instance variables go here
}
//public methods go here
- (void) doAPublicThing;
//properties go here
#end
//in DoThings.m
#interface DoThings (Private)
- (void)doOneThing;
- (void)doAnotherThing;
- (void)stillOtherThings;
#end
#implementation DoThings
- (void) doAPublicThing {
[self doOneThing];
}
- (void) doOneThing {
[self doAnotherThing];
}
- (void) doAnotherThing {
[self stillOtherThings];
}
#end
You need to define these method declarations in your header file for the class:
#interface MyCustomClass : NSObject
- (void) doOneThing;
- (void) doAnotherThing;
#end
Then everything will work as intended.

Objective-C inheritance; calling overridden method from superclass?

I have an Objective-C class that has a method that is meant to be overridden, which is uses in a different method. Something like this:
#interface BaseClass
- (id)overrideMe;
- (void)doAwesomeThings;
#end
#implementation BaseClass
- (id)overrideMe {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (void)doAwesomeThings {
id stuff = [self overrideMe];
/* do stuff */
}
#end
#interface SubClass : BaseClass
#end
#implementation SubClass
- (id)overrideMe {
/* Actually do things */
return <something>;
}
#end
However, when I create a SubClass and try to use it, it still calls overrideMe on the BaseClass and crashes due to doesNotRecognizeSelector:. (I'm not doing a [super overrideMe] or anything stupid like that).
Is there a way to get BaseClass to call the overridden overrideMe?
What you are describing here should work so your problem is likely elsewhere but we don't have enough information to help diagnose it.
From your description, I'd say either the instance you're messaging is not the class you think it is or you made some typo in your code when declaring the method names.
Run your application under gdb, add a symbolic breakpoint on objc_exception_throw, reproduce your problem. Once your process has stopped on the "doesNotRecognizeSelector" exception, print object description and it's class.
Or log it before calling -overrideMe:
NSLog(#"object: %# class: %#", obj, [obj class])
Write a category for BaseClass to override the method.
#interface BaseClass (MyCategory)
- (id) overrideMe;
#end
#implementation BaseClass (MyCategory)
- (id) overrideMe
{
/* Actually do things */
return <something>;
}
#end
Now all instances of BaseClass will respond to selector overrideMe with the new implementation.

Objective C: warning on overriding init

I have a class 'DOInstance' which I inherit later on. Here's its declaration:
#interface DOInstance : NSObject {
}
- (DOInstance *) initWithSynckey:(NSString *)_synckey;
#end
Then I have a subclass of DOInstance:
#interface Workflow_Workitem_Header_1px: DOInstance {
}
//- (Workflow_Workitem_Header_1px *) initWithSynckey:(NSString *)_synckey;
#end
I go ahead and implement it in the implementation file:
- (Workflow_Workitem_Header_1px *) initWithSynckey:(NSString *)_synckey {
[super initWithSynckey:_synckey];
//..
//..
return self;
}
Now, If I do not declare initWithSynckey: (the commented declaration above) in my subclass declaration, I get a warning at the implementation: "warning: initialization from distinct Objective-C type". If I declare it, this warning goes away. Okay.
Moving on:
I later do an instantiation of my subclass:
Workflow_Workitem_Header_1px *instance;
instance = [[Workflow_Workitem_Header_1px alloc] initWithSynckey:#"xxxx"];
Now, this gives me the same warning (irrespective of whether or not I declare the corresponding initWithSynckey: selector in my subclass. Namely, "warning: initialization from distinct Objective-C type".
What am I doing wrong?
Methods named init... should have return type (id), not the type of the class. Check out NSString.h and NSArray.h (among other classes) for examples. That may be what is causing your problem.
In this case, the overriding method must return the same type as the superclass' declaration.
DOInstance defines this:
- (DOInstance *) initWithSynckey:(NSString *)_synckey;
so Workflow_Workitem_Header_1px must look like this:
#interface Workflow_Workitem_Header_1px: DOInstance {
}
- (DOInstance *) initWithSynckey:(NSString *)_synckey;
#end
Any time you get the warning "warning: initialization from distinct Objective-C type" you're doing something in contravention of your typing: changing a method signature, and the like.

Method signature for a Selector

I'm new to the Objective C business (Java developer most of the time) and am woking on my first killer app now. :-)
At the moment I am somehow confused about the usage of selectors as method arguments. They seem to be a little bit different than delegates in C# for example.
Given the following method signature
-(void)execute:(SEL)callback;
is there a way to enforce the signature for the selector passed to such a method?
The method is expecting a selector of a method with the following signature
-(void)foo:(NSData*)data;
But the SEL (type) is generic, so there is a good chance to pass a wrong selector to the
execute method. OK at least at runtime one would see a funny behavior... but I would like to see a compiler warning/error when this happens.
The quick answer is: no, there is no way to have the compiler enforce the method signature of a method selector that is provided via a SEL argument.
One of the strengths of Objective-C is that it is weakly-typed language, which allows for a lot more dynamic behaviour. Of course, this comes at the cost of compile-time type safety.
In order to do what (I think) you want, the best approach is to use delegates. Cocoa uses delegates to allow another class to implement "callback"-type methods. Here is how it might look:
FooController.h
#protocol FooControllerDelegate
#required:
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
#end
#interface FooController : NSObject
{
id <FooControllerDelegate> * delegate;
}
#property (assign) id <FooControllerDelegate> * delegate;
- (void)doStuff;
#end
FooController.m
#interface FooController (delegateCalls)
- (void)handleData:(NSData *)data;
#end
#implementation FooController
#synthesize delegate;
- (id)init
{
if ((self = [super init]) == nil) { return nil; }
delegate = nil;
...
return self;
}
- (void)doStuff
{
...
[self handleData:data];
}
- (void)handleData:(NSData *)data
{
if (delegate != nil)
{
[delegate handleData:data forFoo:self];
}
else
{
return;
// or throw an error
// or handle it yourself
}
}
#end
Using the #required keyword in your delegate protocol will prevent you from assigning a delegate to a FooController that does not implement the method exactly as described in the protocol. Attempting to provide a delegate that does not match the #required protocol method will result in a compiler error.
Here is how you would create a delegate class to work with the above code:
#interface MyFooHandler <FooControllerDelegate> : NSObject
{
}
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
#end
#implementation MyFooHandler
- (void)handleData:(NSData *)data forFoo:(FooController *)foo
{
// do something here
}
#end
And here is how you would use everything:
FooController * foo = [[FooController alloc] init];
MyFooHandler * fooHandler = [[MyFooHandler alloc] init];
...
[foo setDelegate:fooHandler]; // this would cause a compiler error if fooHandler
// did not implement the protocol properly
...
[foo doStuff]; // this will call the delegate method on fooHandler
...
[fooHandler release];
[foo release];
To directly answer your question, no, the SEL type allows any type of selector, not just ones with a specific signature.
You may want to consider passing an object instead of a SEL, and document that the passed object should respond to a particular message. For example:
- (void)execute:(id)object
{
// Do the execute stuff, then...
if ([object respondsToSelector:#selector(notifyOnExecute:)]) {
[object notifyOnExecute:self];
}
// You could handle the "else" case here, if desired
}
If you want to enforce the data handling, use isKindOfClass inside your selector. This works a lot like instanceof which you are familiar with in Java.