i working with geocoding at the moment. The geocoding service allways works with delegates.
So let's say, I've got a
AskingClass and AnsweringClass(geocoding)
The AskingClass calls a function in the AnsweringClass to return the adress of the current location.
AnsweringClass should handle and capsulate the geocoding stuff. My Problem is, with all these delegates, I do not manage to come back to the orginal function, which the asking class has called. So I cannot give easily the adress back:
AskingClass.Adress= [AnsweringClass giveAdress];
I managed it, doing it with delegates, so the result comes back in a delegate function (somewhere) in the askingClass. But I'm not happy with that. It's seems oversized and complex.
with best regards
Klaus-Dieter
It is unclear why you are using a delegate pattern at all. Why not just use straight up classes?
Something like this (assuming that you are using a PCH file for your header files or otherwise importing 'em as needed):
AnsweringClass.h
#interface AnsweringClass:NSObject
- (MyAnswer *)answerThisDude;
#end
AskingClass.h
#class AnsweringClass; // just in case you including AskingClass.h before AnsweringClass.h
#interface AskingClass : NSObject
// {
// declare the ivar if you need support for 32 bit "classic" ABI
// AnsweringClass *theThingThatAnswers;
// }
#property(retain) AnsweringClass *theThingThatAnswers;
#end
Then you can do this:
AskingClass.m
#implementation AskingClass
#synthesize theThingThatAnswers;
- (void) setUpMyStuff // probably invoked by your designated initializer or app launch handler
{
self.theThingThatAnswers = [AnsweringClass new];
MyAnswer *theFirstAnswer = [self.theThingThatAnswers answerThisDude];
}
// don't forget a -dealloc if you aren't running GC'd
#end
No delegation necessary.
Related
I have a static library that is currently sending responses using NSNotificationCenter. But I feel like delegates would be a better solution. The problem is how do I call the delegate methods when I do not know their headers yet. Im not sure how to implement the stuff that is not up to me when the library is in use.
So is there a good of allowing the user to create their own methods and the library calling them when they are needed?
Delegates are often communicated with by you declaring a protocol which specifies the set of callbacks.
#protocol MONImageGeneratorObserver <NSObject>
#required
// called when an image has been generated
- (void)generatedImageWasSavedToURL:(NSURL *)pURL;
- (void)imageGenerationDidComplete;
#end
Then you can tell your client the interface they must implement by specifying the protocol in your APIs:
- (void)setImageGeneratorObserver:(NSObject<MONImageGeneratorObserver>*)pObserver;
Another good way to accomplish this is provide a parameter which is a block. You'll usually want to copy that block when you receive it. Then you don't need to know anything about the client's code.
Your API should be very specific:
that you copy it
on which thread the block will be performed
#interface MONObject : NSObject
+ (void)performAsynchronousLoadWithSuccessfulCallback:(void(^)(void))pSuccess errorCallback:(void(^)(NSError *))pError;
#end
#implementation MONObject
+ (void)performAsynchronousLoadWithSuccessfulCallback:(void(^)(void))pSuccess errorCallback:(void(^)(NSError *))pError
{
if (random()%2) {
// load succeeded!
pSuccess();
}
else {
// load failed = =
NSError * e = ...;
pError(e);
}
}
#end
In both cases, you specify the interface and do not need to see their headers in your implementation. They can call their own methods in the block body or in their definitions of MONImageGeneratorObserver callbacks.
In the apps I worked on, I often found such lines of code
[delegate aFunction];
that generated the "instance method "aFunction" not found (return type defaults to id)" warning
Now, I did a bit of research on SO and found out that the warning can be removed by declaring the function for cases when you call it on self ([self aFunction];), but none of the answers said anything about my case, when I use a delegate.
So, long story short, what can I do to correctly call a delegate's method inside another class?
Things appear to work fine, so this is not a major issue, but a warning means I'm not doing something completely correct so I would like to learn what's the best practice for such cases
Thank you for your help in advance!
So, if I'm understanding you correctly, your issues can be taken away by declaring your protocol as follows:
#class SomeClass;
#protocol SomeClassDelegate <NSObject>
#required
- (void)thisObjectDidSomething:(SomeClass*)instance;
#optional
- (void)thisObjectDidSomethingUnimportant:(SomeClass*)instance;
#end
Then your delegate ivar and property look like this (use assign instead of weak if you're not using ARC):
#interface SomeClass () {
__weak id<SomeClassDelegate> delegate_;
}
#property (weak) id<SomeClassDelegate> delegate;
And in the .h file of any class that's going to implement that protocol, do this:
#interface TCReader : NSObject <SomeClassDelegate> {
}
Since it's safe to call selectors on nil, for required methods, you can just:
[self.delegate thisObjectDidSomething:self]
But for optional methods, you'd better:
if ([self.delegate respondsToSelector:#selector(thisObjectDidSomethingUnimportant:)]) {
[self.delegate thisObjectDidSomethingUnimportant:self]
}
The main point here is that by declaring and making use of a protocol, you let XCode know that those methods are defined for objects implementing the protocol. If you require that your delegate implement that protocol, then Xcode knows that your delegate has those methods defined.
When using categories, you can override implementation methods with your own like so:
// Base Class
#interface ClassA : NSObject
- (NSString *) myMethod;
#end
#implementation ClassA
- (NSString*) myMethod { return #"A"; }
#end
//Category
#interface ClassA (CategoryB)
- (NSString *) myMethod;
#end
#implementation ClassA (CategoryB)
- (NSString*) myMethod { return #"B"; }
#end
Calling the method "myMethod" after including the category nets the result "B".
What is the easiest way for the Category implementation of myMethod to call the original Class A myMethod? As near as I can figure out, you'd have to use the low level calls to get the original method hook for Class A and call that, but it seemed like there would be a syntactically easier way to do this.
If you want a hackish way to do this that involves mucking with the objective-c runtime you can always use method swizzling (insert standard disclaimers here.) It will allow you to store the different methods as arbitrariliy named selectors, then swap them in at runtime as you need them.
From comp.lang.objective-C FAQ listing: "What if multiple categories implement the same method? Then the fabric of the Universe as we know it ceases to exist. Actually, that's not quite true, but certainly some problems will be caused. When a category implements a method which has already appeared in a class (whether through another category, or the class' primary #implementation), that category's definition overwrites the definition which was previously present. The original definition can no longer be reached by the Objective-C code. Note that if two categories overwrite the same method then whichever was loaded last "wins", which may not be possible to predict before the code is launched."
From developer.apple.com: "When a category overrides an inherited method, the method in the category can, as usual, invoke the inherited implementation via a message to super. However, if a category overrides a method that already existed in the category's class, there is no way to invoke the original implementation"
Check out my article about a solution found on the Mac Developer Library:
http://codeshaker.blogspot.com/2012/01/calling-original-overridden-method-from.html
Basically, it's the same as the above Method Swizzling with a brief example:
#import <objc/runtime.h>
#implementation Test (Logging)
- (NSUInteger)logLength {
NSUInteger length = [self logLength];
NSLog(#"Logging: %d", length);
return length;
}
+ (void)load {
method_exchangeImplementations(class_getInstanceMethod(self, #selector(length)), class_getInstanceMethod(self, #selector(logLength)));
}
#end
With the swizzling "helper" methods included in ConciseKit, you actually call the default implementation… weirdly enough.. by calling your SWIZZLED implementation..
You set it up in + (void) load, calling + (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass;, i.e.
[$ swizzleMethod:#selector(oldTired:)
with:#selector(swizzledHotness:) in:self.class];
and then in the swizzled method.. let's suppose it returns -(id).. you can do your mischief, or whatever reason you are swizzling in the first place… and then, instead of returning an object, or self, or whatnot..
return [self swizzledHotness:yourSwizzledMethodsArgument];
As explained here…
In this method, it looks like we're calling the same method again, causing and endless recursion. But by the time this line is reached the two method have been swapped. So when we call swizzled_synchronize we're actually calling the original method.
It feels and looks odd, but.. it works. This enables you to add endless embellishments to existing methods, and still "call super" (actually self) and reap the benefits of the original method's handiwork… even without access to the original source.
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 .
I recently began trying my hand at using protocols in my Objective-C development as an (obvious) means of delegating tasks more appropriately among my classes. I completely understand the basic notion of protocols and how they work. However, I came across a roadblock when trying to create a custom protocol that in turn implements another protocol. I since discovered the solution, but I am curious why the following DOES NOT work:
#protocol STPickerViewDelegate < UIPickerViewDelegate >
- ( void )customCallback;
#end
#interface STPickerView : UIPickerView
{
id < STPickerViewDelegate > delegate;
}
#property ( nonatomic, assign ) id < STPickerViewDelegate > delegate;
#end
Then in a view controller, which conforms to STPickerViewDelegate:
STPickerView * pickerView = [ [ STPickerView alloc ] init ];
pickerView.delegate = self;
- ( void )customCallback
{
...
}
- ( NSString * )pickerView:( UIPickerView * )pickerView titleForRow:( NSInteger )row forComponent:( NSInteger )component
{
...
}
The problem was that pickerView:titleForRow:forComponent: was never being called. On the other hand, customCallback was being called just fine, which isn't too surprising. I don't understand why STPickerViewDelegate, which itself conforms to UIPickerViewDelegate, does not notify my view controller when events from UIPickerViewDelegate are supposed to occur. Per my understanding of Apple's documentation, if a protocol (A) itself conforms to another protocol (B), then a class (C) that conforms to the first protocol (A) must also conform to the second protocol (B), which is exactly the behavior I want and expected.
What I ended up doing was removing the id< STPickerViewDelegate > delegate property from STViewPicker and instead doing something like the following in my STViewPicker implementation where I want to evoke customCallback:
if ( [ self.delegate respondsToSelector:#selector( customCallback ) ] )
{
[ self.delegate performSelector:#selector( customCallback ) ];
}
This works just fine, but I really am puzzled as to why my original approach did not work.
The problem was that UIPickerView already has a delegate member variable, and you were declaring another one in a subclass which was what was being set, while the superclass's delegate variable remained nil and therefore any delegate methods would not be called on the class you expect it to be called on. In this case what you did is pretty much the only way to do it; if you need to extend the given protocol do so, have a class implement that, then just set the class as the UIPickerView's delegate.
Edit: btw, awesome avatar :)
I tried to do something similar - I assume you want to group extra methods you add to the UIImagePickerControllerDelegate in one file? I was running a UIImagePicker from two places and wanted it to behave the same way without duplicating code.
What I did was to add a category to the UIViewController, like this (below.) I'm fairly new to Objective-C (have used C++ for many years) so assuredly this probably violates the spirit of how you are "supposed" to do things (extending the protocol makes more sense), but my approach accomplished what I wanted, so I thought I'd toss it out.
UIViewController+imagePickerDelegate.h:
#interface UIViewController (ImagePickerDelegate) <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
-(void)configurePicker:(UIImagePickerController*)picker;
...
#end
UIViewController+imagePickerDelegate.m:
#import "UIViewController+imagePickerDelegate.h"
#implementation UIViewController (ImagePickerDelegate)
-(void)configurePicker:(UIImagePickerController*)picker
{
picker.delegate = self;
picker.allowsEditing = YES;
}
....
#end