I was using method swizzling to wrap all method invocations in a class with some extra functionality. Specifically I was:
Checking if the required object for this method call was in the cache
If the cache had that object return it.
If not, dispatch to the original implementation, populate the cache and return that.
For each method, I would reroute to an advised method. And implement the new method using + (BOOL)resolveInstanceMethod:(SEL)sel and IMP_implementationWithBlock.
It worked fine, but the code didn't read nicely. It seems NSProxy will provide a neater way to implement this functionality.
But still another alternative, would be to simply have an NSObject subclass stand-in and intercept method calls around my target object's methods. By overriding forwardInvocation and methodSignatureForSelector, I can get the required outcome.
So what does NSProxy give me? Why should I use this instead?
The point of NSProxy is that it doesn't implement most methods. That's necessary to be sure that the Objective-C forwarding machinery gets invoked to begin with. If you start with NSObject, there are a lot of methods which will just be directly dispatched without you having an opportunity to forward them.
Related
yesterday a colleague asked, why we should not declare an init method (initWith...:(...)) in a protocol to force implementing classes to supply such an initializer. I was quite suprised about that question and in my understanding, this is nonsense. But I could not find a definitive reason but that declaring an init method in a protocol leads to less flexibility for the implementations.
Could you please tell me a good reason, why there should or should not be an init method in a protocol?
Thanks!
You define methods in protocols so that your code could call methods implemented by others. The "contract" between you and developers implementing your protocol looks like this:
You define the protocol,
Someone else implements your protocol,
Someone else creates an object implementing your protocol, and gives it to you, so
You can call methods of your protocol without knowing their implementation.
In order to call methods of your protocol, you need to have an instance of an object implementing it. The whole point of defining protocols is removing from your code any knowledge about the class implementing your protocol: if you know which class you are going to get, you might as well skip the protocol, and program to the class directly. However, if you want to call your init, you have to either know the class, or someone else must pass you an alloc-ed object on which the init has not been called yet. Neither alternative is a good idea - the first one kills the purpose of having protocols, and the second forces your callers deal in partially initialized objects.
Note that it does not prevent you from having non-init configuration methods in a protocol: if all objects must be configured using certain bits of information, let your users implement whatever init that they want, and add a configureWith:... method to your protocol, letting you control the process of configuring the object without knowing about its init method.
I know some protocols in iOS SDK which has init... methods. For example NSCoding Protocol has – initWithCoder: required method. I think it is normal practice.
Does objective-c offer a way to intercept calls to class method that does not exist?
The forwardInvocation method is what you are going to want to use. It is called automatically when a non-existent selector is called on an object. The default behavior of this method is to call doesNotRecognizeSelector:(which is what outputs debug information to your console), but you can override it do anything you want. One recommended approach by Apple is to have this method forward the method invocation to another object.
- (void)forwardInvocation:(NSInvocation *)anInvocation
Note that forwardInvocation is a fairly expensive operation. An NSInvocation object needs to be created by the framework and (optionally) used to invoke a selector on another instance. If you are looking for a (relatively) faster method of detecting non-existent selectors then you can choose to implement forwardingTargetForSelector instead.
- (id)forwardingTargetForSelector:(SEL)aSelector
You should Apple's documentation for how to override these methods effectively, there are some gotcha's to watch out for, particularly when overriding the forwardInvocation method on the same object that will have the missing selectors.
Yes, you can with the resolveClassMethod: class method (which is defined on NSObject):
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html
Here is also something to watch out for (stumped me the first time): http://iphonedevelopment.blogspot.com/2008/08/dynamically-adding-class-objects.html
I want to go to there. Seriously though, how does one implement a pure virtual method in an "Apple" way? Do you use a Protocol with your base class and throw exceptions on those methods?
When you program in Objective-C you need to purge your mind of such things as virtual methods. You don't call methods on Objective-C objects, you send messages to them. Objects either respond to messages or they don't, but due to the dynamic binding, you can't tell this until run time.
Thus, you can declare a method on a base object and not not provide an implementation, no problem (except for the compiler warning), but you can't have the compiler flag up when you directly instantiate an object with such methods and it won't throw an error at runtime unless you actually send that message to the object.
The best way to create "virtual" base classes (in my opinion) is to declare the method and give it a stub implementation that throws a suitable exception.
In Objective-C, there is no pure virtual support as in C++.
A simulation would be that you declare a method in your interface but don't implement it in your .m file. Of course you'd get compiler warnings but IIRC you can turn those off. But you won't get warnings/errors if you don't overwrite them in the subclass, which you get in C++ (IIRC).
An alternative would be to implement them with just an NSAssert(NO, #"Subclasses need to overwrite this method"); body. Still, you'd only catch this at runtime, not compiletime.
Depending on what you're doing the delegate pattern may be more appropriate than a subclass, where the delegate is defined as id<YourDelegateProtocol>. The compiler will generate a warning if the required methods in the delegate protocol are not implemented.
Subclassing is generally avoided in Objective-C since objects cannot inherit from multiple superclasses but they can implement multiple protocols.
You should use the:
- (void)doesNotRecognizeSelector:(SEL)aSelector method.
As noted by Apple, here: https://developer.apple.com/library/mac/#documentation/cocoa/reference/Foundation/Classes/NSObject_Class/Reference/Reference.html
You have a few options, but you're on the right track.
ObjC doesn't support this directly, forcing subclasses to implement a protocol is the best way to check it at compilation.
'Secretly' implementing the method in the base class and asserting is what I do to confirm the subclasser has subclassed correctly at runtime. Some people have mixed feelings about assertions, or must leave them active, so that's not always a good solution.
You can also force subclasses use a specific class constructor and initialization sequence, then verify they have implemented everything required before returning an instance, in case compiler warnings don't cut it.
But ObjC is missing some lang features which allow clients to shoot themselves in the foot, or workaround what they wish so... you shouldn't get too stuck on enforcing it.
note: Exceptions are very uncommon (and a bit unsafe, too) in ObjC.
A virtual method is a method whose behavior can be overridden within an inheriting class by a function with the same signature (i.e same name with same number of params and type of params).
Example:-
#implementation BaseClass
-(void)viewDidLoad
{
[self virtualMethod:123];
}
-(void)virtualMethod:(int)param
{
//implement this method in subclass
}
#end
////////////////////////////////////////////////////
#interface ChildClass:BaseClass
#end
#implementation ChildClass
-(void)virtualMethod:(int)param
{
NSLog(#"There is no keyword "Virtual" in Objective C.");
}
#end
Output:-
"There is no keyword "Virtual" in Objective C."
Sorry for noobness-level of the question.
I saw this answer, where it says
Add something like this to your NSURLConnection delegate
However, the method in question, sendSynchronousRequest:returningResponse:error:, is a class method. If I understand delegate methods correctly, they use a delegate which is specified when the NSURLConnection object is initiated.
So, if I have no instance of the class, a delegate can't be used. Did I understand correctly?
Yes, you are correct. In Cocoa, assigning a delegate requires an instance. In the case of NSURLConnection, its delegate is supposed to be used when making an asynchronous request that is initiated with -initWithRequest:delegate: or +connectionWithRequest:delegate:
Since classes are also objects it could be conceived that they also could have delegates. However, since there is no concept of class variables in Objective-C, a class would have nowhere to store its delegate (it could use a standard C variable in its .m file, though). Anyway, this concept is not used in Cocoa.
Yes delegates are used for handling events when you send your request asynchronously.
While sending synchronous request using +sendSynchronousRequest:returningResponse:error: method delegates are not used - you only get the resulting data and (optionally) server response and error and not aware about intermediate loading events (and remember that calling thread is also blocked while connection is in progress).
I'm using the delegate pattern for one of my objects. My idea is that I will be able to swap the delegate out later for a different delegate implementing a different strategy. I suppose this is just as much the strategy pattern as the delegate pattern.
My question is, is it bad practice for my delegate to have a reference back to the object for which it is the delegate? There are a couple properties of that object that I need to have access to regardless of which delegate/strategy I use. If this is bad form, how should I get access to the properties?
Not necessarily. For example, it's quite common for a "controller"-type object to create data objects and views and make itself the delegate of some of those objects in order to properly control things.
It is not at all bad practice. The delegate pattern allows for a class to have a generic way to talk to any number of objects as long as the implement the same protocol. But the class on which you set the delegate also will usually have a number of public properties or methods that allow you to query or alter what the class is doing, in response to which the class may in turn trigger a number of the delegate calls. So you need a reference of the class to which you are the delegate, in order to tell the object to do something different than it is already, and of course to release it when you are through with it!
This is also why it's important to always have any delegate properties as assign, and not retain, properties. That way when the originating class is released it will actually be released, instead of having delegate objects it is holding onto causing a retain loop that keeps both around.
It's also why whenever you are being released, you should set the delegate reference to nil in anything you may have a delegate reference set. This way a class will not have an invalid delegate reference if the delegate is released before the class that uses a delegate.
Generally a dependency should not have a reference back to the dependent object, as this would be a classical circle reference. To avoid having a back-reference you can supply the needed properties as arguments in a delegate method, or you move the properties themselves into the delegate.
I'd say yes, it's bad practice. The idea behind a delegate is that it's effectively a standalone object that receives messages about the object for which it is the delegate (the "delegator"). The delegator should have a reference to the delegate, not the other way around, otherwise it's not a true delegation relationship anymore.
A preferred way to accomplish what you're asking is to provide the sending object along with whatever message your delegate receives. For example, on your delegate, instead of having a delegator property and then receiving, for example, a didDoSomething:(id)anObject method, you could remove the delegator property and send the message delegator:(id)anObject didDoSomething:(id)anotherObject. This way, you keep the delegate distinct from the delegator, but still get access to the delegator's properties when you need them.
This way also has the advantage of not providing access to the delegator in methods when you don't truly need it; for example, your delegate could have a didDoSomething method that takes no arguments, not even a delegator, and is just used for logging, as well as a delegator:(id)anObject didSomethingElse:(id)anotherObject method that calls some properties on the delegator and is much more involved.
Finally, this method allows you to use the same delegate for multiple delegators, since you don't need to update a delegator property for each delegate object.
For a good example of how this works, take a look at the NSURLConnection documentation, specifically its delegate methods - a lot of them take the form connection:didDoSomething:, where the first argument is the connection calling the delegator. Developers commonly define a single connection delegate for multiple connections, implementing their delegate methods to do different things depending on properties of the NSURLConnection object passed in.