There is a similar question to mine on the following link
but it doesn't quite answer my query.
I am setting a helper class for Facebook (follows the delegation pattern) . An example of one of the class methods would be:
+ (void)openSession:(id)delegate;
This method calls a the Facebook openActiveSessionWithReadPermissions method which expects a completionHandler block. Would it make sense to call the delegate method, say sessionStateChanged in the block as follows?
[delegate sessionStateChanged];
Or is it better to use instance methods for the Facebook helper class and call the delegate using [self.delegate sessionStateChanged] in the completionHandler block.
You would be better off with a block parameter rather than a delegate as a parameter if it is just for a single callback.
+ (void)openSession:(void (^)(void))sessionStateChangedBlock
That way you don't have to worry about defining a delegate protocol.
If you want to use a delegate, you will have to define a delegate variable at the class level. You can't use [self.delegate sessionStateChanged] because you are saving the delegate as a class variable. self is only available in an instance of the class.
I tried both methods i.e. using class and instance methods. Any of them will do, though to follow the proper delegation pattern I believe using instance methods is more appropriate.
Related
Is it possible to initialize a property in a category?
For example, if I have a mutable array property called nameList in a class. Is it possible to have a category created for this class to add an object to the array property before any of the category method is called?
If I understand you correctly, and others are interpreting your question differently, what you have is:
A class with a property
A category on that class
And you want to call a particular method automatically before any category method is called on a given instance, that method would "initialise" the category methods by modifying the property.
In other words you want the equivalent of a subclass with its init method, but using a category.
If my understanding is correct then the answer is no, there is no such thing as a category initializer. So redesign your model not to require it, which may be to just use a subclass - as that provides the behaviour you are after.
The long answer is you could have all the category methods perform a check, say by examining the property you intend to change to see if you have. If examining the property won't determine if an object has been "category initialized" then you might use an associated object (look in Apple's runtime documentation), or some other method, to record that fact.
HTH
Addendum: An even longer/more complex solution...
GCC & Clang both support a function (not method) attribute constructor which marks a function to be called at load time, the function takes no parameters and returns nothing. So for example, assume you have a class Something and a category More, then in the category implementation file, typically called Something+More.m, you can write:
__attribute__((constructor)) static void initializeSomethingMore(void)
{
// do stuff
}
(The static stops the symbol initializeSomethingMore being globally visible, you neither want to pollute the global name space or have accidental calls to this function - so you hide it.)
This function will be called automatically, much like a the standard class + (void) initialize method. What you can then do using the Objective-C runtime functions is replace the designated initializer instance methods of the class Something with your own implementations. These should first call the original implementation and then an initialize your category before returning the object. In outline you define a method like:
- (id) categoryVersionOfInit
{
self = [self categoryVersionOfInit]; // NOT a mistake, see text!
if (self)
{
// init category
}
return self;
}
and then in initializeSomethingMore switch the implementations of init and categoryVersionOfInit - so any call of init on an instance of Something actually calls categoryVersionOfInit. Now you see the reason for the apparently self-recursive call in categoryVersionOfInit - by the time it is called the implementations have been switched so the call invokes the original implementation of init... (If you're crosseyed at this point just draw a picture!)
Using this technique you can "inject" category initialization code into a class. Note that the exact point at which your initializeSomethingMore function is called is not defined, so for example you cannot assume it will be called before or after any methods your target class uses for initialization (+ initialize, + load or its own constructor functions).
Sure, it possible through objc/runtime and objc_getAssociatedObject/objc_setAssociatedObject
check this answer
No it's not possible in objective c.Category is the way to add only method to an existing class you can not add properties in to this.
Read this
Why can't I #synthesize accessors in a category?
In Objective C, a custom init method must call the superclass's designated initializer. Consider the following custom init method for a sublcass of NSView:
- (void)initWithFrame:(CGRect)aFrame andName:(NSString *)aName {
if(self = [super initWithFrame:aFrame]){
//set up object
}
}
However, MacRuby only offers the super keyword, which simply tries calling the same method in the superclass. Since this is a custom initializer, however, the superclass has no such method.
What is the standard way of solving this? I did see this question: MacRuby custom initializers but I can't say I understand the answer very well, nor does it seem to be some broadly accepted solution. Since MacRuby is now a few years older than when that post was written, I'm hoping a clearer, standard solution now exists.
In rubymotion (and I think MacRuby shares this behavior) there are TWO types of classes: pure Ruby, which use initialize, and classes derived from an objective-c class. It is best not to mix the two. If you are subclassing a objective-c class, you should use an init method. your initialize method will never get called!
This is because the NSObject##new method calls init, not initialize (actually even this is an oversimplification, but the abstraction works).
your example above is confusing because you are calling init instead of initWithFrame. You MUST call the designated initializer of the parent class - in this case, using super.
If the initializer you call (in this case, init, calls your initializer, you're using the wrong one - there's no escaping the recursion cycle in that case.
So you can't exactly CHOOSE which method to call on the parent. You can, however, use your own init method:
def initWithTitle(title)
initWithFrame(CGRectZero)
#title = title
return self
end
I would write this method like this:
def initWithTitle(title)
initWithFrame(CGRectZero).tap do
#title = title
end # that way I never forget to return self
end
If I understand you correctly, you want to create your own custom initialize method in rubymotion but still call the original init method.
I frequently do something like this:
#custom initializer
def initialize
self.init # <--calls 'init' from parent
#stuff happens here
end
Instead of calling super, just call the init method, this works because your object is already allocated by the time it reaches initialize. And if you have variables to pass then pass them to what ever method is considered the initializer.
(Edit: Probably need self.)
I have a questions about the iPhone application. I am the green of the iPhone application. When I read the document(PDF) download from the apple developer website (online version). I found that the document always mentions different methods of the library.
There are
1) Class method
2) Instance method
3) Delegate method
I understand the use and meaning of the instance method, which is called by a instance.
let's say the delegate methods is the connection:didReceiveAuthenticationChallenge and the class method sendSynchronousRequest:retruningResponse:error:.
However, I don't understand about the different between the class method and the delegate method. Is the class method for the whole class? or whole project? What it means of the delegate? and where should I put the code after I modify the content of the delegate? How can I call the method?
Can anyone help me. Thank you very much.
It is another question about the delegate method. And I don't how to solve the problems. Please help me. Thank you.
HTTP status code = 0 (iPhone) (objective c)
Suppose you have a class Foo and an instance of that, Foo* foo.
Then, the class method is a method which is sent to the class:
[Foo classMethod];
while the instance method is a method sent to the instance:
[foo instanceMethod];
The delegate method is a method which the instance of the class calls. So, you typically implement another class Delegate with an instance Delegate* delegate, and do
[foo setDelegate:delegate];
Then, the object foo calls the delegate method of delegate at appropriate times:
[delegate delegateMethod];
This is a way to receive an event from the system API.
Apple provides extensive documentation on the fundamentals for Objective-C and Cocoa - if in doubt, this should be your first stop.
The Objective-C Programming Language - Class Objects:
[...] a class definition can include methods intended specifically for the class object—class methods as opposed to instance methods. A class object inherits class methods from the classes above it in the hierarchy, just as instances inherit instance methods.
Cocoa Fundamentals Guide - Delegates and Data Sources:
A delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program.
The delegating object is often a responder object—that is, an object inheriting from NSResponder in Application Kit or UIResponder in UIKit — that is responding to a user event. The delegate is an object that is delegated control of the user interface for that event, or is at least asked to interpret the event in an application-specific manner.
And some related background in The Objective-C Programming Language - Protocols:
Class and category interfaces declare methods that are associated with a particular class — mainly methods that the class implements. Informal and formal protocols, on the other hand, declare methods that are independent of any specific class, but which any class, and perhaps many classes, might implement.
A delegate method is a method that is defined in a classes delegate protocol. They are added to your class but your class must have the objects delegate protocol. They are usually used by the object but is something that you must define for the object. NSTableView and UITableView use delegate methods to populate their data. A class method is just one that you define in your interface.
I've many classes in my XCode project, and only the class from where the control comes from main.m will be having applicationDidFinishlaunching method. in my other classes will the methods in it knows how to go to its own method implementation, or do i need to write init method?
I'm not sure I understand what you are asking about, but I will try.. :-)
applicationDidFinishLaunching is part of the UIApplicationDelegate protocol. Typically, only one class will implement this protocol in one application.
In you other classes, you implement the init method if you need to do something when an instance of that class is created, like instantiating and initializing property values for that instance.
Can I intercept a method call in Objective-C? How?
Edit:
Mark Powell's answer gave me a partial solution, the -forwardInvocation method.
But the documentation states that -forwardInvocation is only called when an object is sent a message for which it has no corresponding method. I'd like a method to be called under all circumstances, even if the receiver does have that selector.
You do it by swizzling the method call. Assuming you want to grab all releases to NSTableView:
static IMP gOriginalRelease = nil;
static void newNSTableViewRelease(id self, SEL releaseSelector, ...) {
NSLog(#"Release called on an NSTableView");
gOriginalRelease(self, releaseSelector);
}
//Then somewhere do this:
gOriginalRelease = class_replaceMethod([NSTableView class], #selector(release), newNSTableViewRelease, "v#:");
You can get more details in the Objective C runtime documentation.
Intercepting method calls in Objective-C (asuming it is an Objective-C, not a C call) is done with a technique called method swizzling.
You can find an introduction on how to implement that here. For an example how method swizzling is implemented in a real project check out OCMock (an Isolation Framework for Objective-C).
Sending a message in Objective-C is translated into a call of the function objc_msgSend(receiver, selector, arguments) or one of its variants objc_msgSendSuper, objc_msgSend_stret, objc_msgSendSuper_stret.
If it was possible to change the implementation of these functions, we could intercept any message. Unfortunately, objc_msgSend is part of the Objective-C runtime and cannot be overridden.
By googling I found a paper on Google Books: A Reflective Architecture for Process Control Applications by Charlotte Pii Lunau. The paper introduces a hack by redirecting an object's isa class pointer to an instance of a custom MetaObject class. Messages that were intended for the modified object are thus sent to the MetaObject instance. Since the MetaObject class has no methods of its own, it can then respond to the forward invocation by forwarding the message to the modified object.
The paper does not include the interesting bits of the source code and I have no idea if such an approach would have side effects in Cocoa. But it might be interesting to try.
If you want to log message sends from your application code, the -forwardingTargetForSelector: tip is part of the solution.
Wrap your object:
#interface Interceptor : NSObject
#property (nonatomic, retain) id interceptedTarget;
#end
#implementation Interceptor
#synthesize interceptedTarget=_interceptedTarget;
- (void)dealloc {
[_interceptedTarget release];
[super dealloc];
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(#"Intercepting %#", NSStringFromSelector(aSelector));
return self.interceptedTarget;
}
#end
Now do something like this:
Interceptor *i = [[[Interceptor alloc] init] autorelease];
NSFetchedResultsController *controller = [self setupFetchedResultsController];
i.interceptedTarget = controller;
controller = (NSFetchedResultsController *)i;
and you will have a log of message sends. Note, sends sent from within the intercepted object won't be intercepted, as they will be sent using the original object 'self' pointer.
If you only want to log messages called from the outside (usually called from delegates; to see which kind of messages, when, etc.), you can override respondsToSelector like this:
- (BOOL)respondsToSelector:(SEL)aSelector {
NSLog(#"respondsToSelector called for '%#'", NSStringFromSelector(aSelector));
// look up, if a method is implemented
if([[self class] instancesRespondToSelector:aSelector]) return YES;
return NO;
}
Create a subclass of NSProxy and implement -forwardInvocation: and -methodSignatureForSelector: (or -forwardingTargetForSelector:, if you're simply directing it on to a second object instead of fiddling with the method yourself).
NSProxy is a class designed for implementing -forwardInvocation: on. It has a few methods, but mostly you don't want them to be caught. For example, catching the reference counting methods would prevent the proxy from being deallocated except under garbage collection. But if there are specific methods on NSProxy that you absolutely need to forward, you can override that method specifically and call -forwardInvocation: manually. Do note that simply because a method is listed under the NSProxy documentation does not mean that NSProxy implements it, merely that it is expected that all proxied objects have it.
If this won't work for you, provide additional details about your situation.
Perhaps you want NSObject's -forwardInvocation method. This allows you to capture a message, retarget it and then resend it.
You can swizzle the method call with one of your own, which does whatever you want to do on "interception" and calls through to the original implementation. Swizzling is done with class_replaceMethod().
A method call, no. A message send, yes, but you're going to have to be a lot more descriptive if you want a good answer as to how.
To do something when a method is called, you could try an events based approach. So when the method is called, it broadcasts an event, which is picked up by any listeners. I'm not great with objective C, but I just figured out something similar using NSNotificationCenter in Cocoa.
But if by "intercept" you mean "stop", then maybe you need more logic to decide wether the method should be called at all.