Is it possible to set up a custom UIResponder subclass? I need to implement a listener for UIEvents (specifically remote control events) that will be delivered through out the course of the app's lifecycle.
I am trying to avoid using UIViewControllers (will be dealloced at some point) and AppDelegate (would like to not burden it if possible) if possible.
Obviously you can subclass UIResponder and you can make an instance of that subclass. The problem is getting that instance into the responder chain, so that its UIResponder methods are actually called, and in such a way that the rest of the responder chain doesn't break. This might be possible — I've certainly done it in Cocoa on the desktop, though never in UIKit on an iOS device — but you would do much better, in my opinion, to give some introspective thought to why you have this peculiar aversion to putting the code where it obviously wants to go (in a UIViewController or in the app delegate).
Related
How would I go about getting my extension to observe a property on the class it's extending while also being able to remove it at a later time?
For example:
I have a UIView, and I'd like to listen for frame changes within my UIView extension. When these changes occur I need to run some code that alters the views appearance based on the new frame.
The problem I'm having is, that while I can set up an observer, I can't figure out a way to remove it. There's no deinit() and I'd like the observer to hang around for the lifecycle of the UIView.
I'd rather not have to put this removal responsibility on the developer, and I don't want to subclass.
It doesn't even have to be KVO, if there's a better way I'd love to know about it.
The usual solution to this is to use an associated object as a deallocation spy. Associated objects are released when their attached object is deallocated, so you can run code in their deinit that you want to fire when the attached object goes away. That said, doing this really well in a multi-threaded world is a little tricky to say the least. I don't recommend building your own. Instead, I suggest PMKVObserver which will handle this for you. Even if you do choose to build your own, you should study how PMKVObserver does its magic so you're not overly naïve in your implementation.
Doing this sloppily (not worrying about multi-threaded race conditions) is not too hard in Swift, but to do it really well is better done in ObjC and bridged to Swift. Again, consult the code for the tricky corner cases.
While
Extensions can add new convenience initializers to a class, but they
cannot add new designated initializers or deinitializers to a class.
Designated initializers and deinitializers must always be provided by
the original class implementation.
So I think you cannot handle it in any nice way without subclassing.
I have a case where I need to modify all instances of NSView, trivial by adding a couple of lines of code to init() but how can that be done cleanly for all subclasses in Swift?
The case I have in mind:
I add a custom property to NSView via an extension
That works fine, but isn't animatable until it's registered as animatable via the layer's addAnimation:forKey: method.
So all I really need to do is ensure that addAnimation:forKey: gets called every time NSView or a subclass gets called.
Things I've considered:
Somehow doing this in an extension. Problem: extensions can't override functions, and without overriding init() or something like viewDidAppear() the code has to be called manually every time (e.g. with a convenience initialiser).
Subclass NSView and add the code. Problem: NSButton, Slider and all the rest won't inherit the code, and I have to subclass them all.
Method swizzling. This should be possible, because obj-c methods are swizzlable and NSView inherits from NSObject.
So far only swizzling seems viable, but I'm reluctant to do this because it's reliant on the APIs staying obj-c friendly, and I don't know how long that will be the case for.
Is there another way?
I'm currently trying to build my own Custom ContainerViewController.
I'm quite familiar with the iOS ViewController containment API (introduced in iOS 5) and the new iOS7 ViewController Transition API.
While implementing my container, i tried to utilize the same patterns UINavigationController and UITabBarController are using.
My Container is working well so far and using animated and interactive transitions properly.
The Problem is, i packed a huge amount of the logic into my UIViewController container subclass. It is conforming to <UIViewControllerContextTransitioning> and uses iVars to store all the values returned by that protocol's methods.
The animation and interaction logic is already separated in another class and third-parties are also able to provide their own transition using a delegate similar to UINavigationControllerDelegate and UITabBarControllerDelegate.
What I'm trying to do now is out-sourcing the UIViewControllerContextTransitioning to a separate class to create the same modularity Apple does for it's containerVCs.
Apple provides a UIViewControllerOneToOneTransitionContext (private API) for the id<UIViewControllerContextTransitioning> object handed to the UIViewControllerAnimatedTransitioning and UIViewControllerInteractiveTransitioning methods. So they are NOT using their UIViewController subclass for that. (That's what i do at the moment)
My current structure is in so far tempting to keep for me as when the transition logic calls [updateInteractiveTransition:], [completeTransition:], etc. on the context, these calls are made directly on my containerController which can then respond by updating other elements in it's view. (Like UINavigationController does when you call [updateInteractiveTransition:] and it's updating the content of the NavigationBar (cross-fade)).
Out-Sourcing the contexttransitioning logic in another class would mean:
Provide the viewControllers and frames, etc. which are hold in the stack of my container FROM the container TO the context object because the context needs to provide them to the transition logic.
Call transition-callbacks FROM the context object ON the container because the context object is the one receiving them from the transition logic.
As Apple uses this class-relationship, there must be some advantage about it, i guess.
Currently, i don't know if i should keep my implementation, or try to make it as modular as Apple-provided containers.
Also see this SO - Question where i asked the same thing. (More like an answer-question, sorry for that :/ )
While we're on the topic : Is it possible to make my container work with UIPercentDrivenInteractiveTransition ? The documentation says it cuts the animation executed by the transitionAnimator in keyframes and automagically "replays" the animated transition step by step, so i doubt it can be used with custom containers.
Thanks for your help !
Apple uses a lot of small classes conforming to certain protocols to hand over pieces of work. Divide and conquer. Have a look at for instance the way UITableView operates or collection view. They did split things into smallest chunks possible, and provided each one with some generic objects. These objects only conform to certain Protocols.
Do not force people to subclass.
Create protocols that classes fulfilling certain roles have to conform to.
Where you want to create ready to use objects that will perform certain actions - return id type of object, not a class object. That's the only way to keep things simple and flexible enough.
Apple does that even with NSObject, which is both a class and protocol.
When creating your own protocols, remember to make them conform to NSObject * protocol.
Your question is rather long, and does not ask any specific questions, so I hope this answers some of your concerns. If not, feel free to post one to response to this.
I used to develop iOS apps using the Objective-C language, and relied on the dealloc method to perform some cleanup/unregister tasks in my application. Now on the MonoTouch (garbage collected) it is not an option anymore.
Suppose I have a UIViewController that adds as a subview of it's View property an instance of MyView (UIView subclass). MyView in turn registers itself to receive some events from another manager/global object so that it knows how to update itself accordingly (e.g.: onlineProfilesManager.Refreshed += () => <update UI with the new state>;).
As long as MyView is on screen, everything is fine. However I must know when it's removed from the screen so that I can unregister MyView from the event handler.
In Obj-C this could be simply done in the dealloc method because when the screen changes the UIViewController is deallocated --> MyView is removed from it's superview and then MyView dealloc method is called.
In Monotouch I don't have this 'deterministic' flow anymore. I tried to put some print statements in the UIViewController and MyView destructors but they are never called (the reason is because the MyView is still registered for the event handler, since I don't know when/how to unregister it, it will never be deallocated).
Does anyone know what is the 'pattern' to handle such situations in MonoTouch? I think I'm missing a fundamental concept and getting into trouble developing my apps.
Thanks in advance.
EDIT
I'm editing my question because looks like the solution for my problem is using the Weak Event Pattern but I didn't find an implementation for the MonoTouch platform.
Does anyone know how can I use the Weak Event Pattern in MonoTouch ?
The best way to handle events is to unregister them in ViewWillDisappear and register them in ViewWillAppear. This means that you can't use anonymous methods though as you don't have a reference to the method to unregister it.
If that doesn't suit what you need, you can do something similar to this http://sgmunn.com/blog/2012/05/non-gcd-event-handlers/
Cheers.
If you are looking for weak events, you can try my "Messenger" implementation here.
It is inspired by what is available in TinyIoC, but I re-implemented it so it used less reflection, etc.
I think to know what the App Delegate does. It has some nice methods like -applicationDidFinishLaunching which will be called when the app has finished launching, and so on. But what's that actually? Is that some object instantiated in the UIApplicationMain function?
And how does it work that every class in my app has access to that App Delegate object? Is there any good graph on the net that visualizes these relationships?
In Cocoa, a delegate is an object that another object defers to on questions of behavior and informs about changes in its state. For instance, a UITableViewDelegate is responsible for answering questions about how the UITableView should behave when selections are made or rows are reordered. It is the object that the UITableView asks when it wants to know how high a particular row should be. In the Model-View-Controller paradigm, delegates are Controllers, and many delegates' names end in "Controller."
At risk of stating the obvious, the UIApplicationDelegate is the delegate for the UIApplication. The relationship is a bit more obvious in Cocoa (Mac) than in Cocoa Touch (iPhone), since the NSApplication delegate is able to control the NSApplication's behavior more directly (preventing the application from terminating for instance). iPhone doesn't permit much control over the UIApplication, so mostly the UIApplicationDelegate is informed of changes rather than having an active decision-making process.
The UIApplicationDelegate isn't strictly available from everywhere in the app. The singleton UIApplication is ([UIApplication sharedApplication]), and through it you can find its delegate. But this does not mean that it's appropriate for every object in an app to talk directly to the app delegate. In general, I discourage developers from having random objects talk to the app delegate. Most problems that are solved that way are better solved through Singletons, NSNotification, or other delegate objects.
As to its creation, on Mac there is nothing magical about the app delegate. It's just an object instantiated and wired by the NIB in most cases. On iPhone, however, the app delegate can be slightly magical if instantiated by UIApplicationMain(). The fourth parameter is an NSString indicating the app delegate's class, and UIApplicationMain() will create one and set it as the delegate of the sharedApplication. This allows you to set the delegate without a NIB (something very difficult on Mac). If the fourth parameter to UIApplicationMain() is nil (as it is in the Apple templates), then the delegate is created and wired by the main NIB, just like the main window.
The object is instantiated in this fashion;
The main-function looks for the main nib set in the info.plist. The nib has as app delegate which is set to some class which must implement UIApplicationDelegates and its required methods. The app delegate then loads some viewcontroller.
It serves as an application wide callback object for events that affects the whole application, such as low-memory, etc.