Is there any possible way to detect every change on User Interface during runtime??
I'm trying to find all objects in the current app interface.
I'm trying to to get all nodes inspecting recursively the main Window, but, for example, how to know if the top viewcontroller changes or if it's added a uiview dynamically, or is presented a modalview??
The main objective is to have a library to do this..
Any idea, help?
Thanks!
You could write your own library based on this, using advanced Objective-C techniques. I do not recommend you to do this, since it mostly breaks MVC patterns on iOS. Depends on what do you want to use it for, maybe analytics?
So these are the options I believe, if you want to actively inspect UIView hierarchy. All options are pretty complicated though.
Swizzle methods such as addSubview and removeFromSuperview of UIView, so you could know when changes like that happens. Including the getters of frame and bounds, if you wish to know the position.
You could use KVO to watch properties such as: subviews, frame, bounds, superview to notice any changes. But at one point you would have to add the same object as the observer (could be singleton).
Decide for an interval that is fired by a NSTimer and go through the hierarchy recursively beginning at keyWindow on UIApplication. This would have a big performance impact though.
There may be other options, but these are the ones I believe to be the best choices.
Related
I want to practice creating simple apps using no storyboard. I am able to do the constraints programmatically (slowly) but I want to also practice separating my code into MVC. Is there a particular place/method that I am supposed to write the programatic constraints? Or does it not matter?
Good discussion in the comments. My thoughts, based on that discussion?
With an understanding that the question is subjective, you place your constraints:
The earliest in a view controller's life cycle where they work.
As "close" to the view as possible.
If it's something common, make it as universal as possible.
Understand how your specifics fit into everything.
(Understand, the question isn't limited to constraints. It could apply to hierarchies, UI, even database tables when you get down to it!)
Sticking to constraints, and my answer....
(1) Use the UIViewController and UIView lifecycles.
Generally the view life cycle is loadView, viewDidLoad, viewWillAppear, viewWillLayoutSubviews, viewDidLayoutSubviews, and viewDidAppear. great SO answer detailing this.
I believe that loadView is too early for constraints, but not viewDidLoad - **provided you aren't expecting to know the frame size. While many say viewDidLayoutSubviews is the right place for that, I've found that viewWillLayoutSubviews most times works just as well. Either way, get your constraints set as soon as possible!
(2) Do it as close to the view as possible.
If you have subviews - I have a "ToolBar" class of objects - you want the constraints, at least as much as possible, to be coded inside the class. For instance, in my tool bar, it slides out, has buttons, and even rotates upon orientation. The only constraints not inside these classes is for orientation - that owner is (and I believe should be) the view controller instantiating it.
(3) Make it universal.
I plan to use this tool bar across a few apps. So the first thing I did was add it to a framework. This framework was needed because I had an app that I delivered a photo editing exension - and the "edit" screen is as much the same as possible. In the end I move all my constraints there. (At least as much as possible.) Anything that I believe is reusable.
(4) Understand the specific requirements of your app.
This should be obvious. If you need to code for various orientations, use arrays and activate/deactivate them. (YES, a common mistake is replacing them! That's setting yourself up for some major headaches.)
If you can keep things active, declare the constraint, set `isActive = true1, and forget about it. If you need to adjust that constraint's constant or multiplier, in the declaration name it and then where you need to alter it, do it.
My conclusion? Auto layout is a very useful tool - more so in code. But the placement of code is like asking "how does one code an OOP app for auto rentals" or " how does one design a database for auto rentals". It not just an art, there are many answers. These are the "rules" I try to follow - YMMV.
To get started with this style of development I recommend checking out Let's Build That App as he goes through very in-depth examples of setting up complex apps entirely in code, without storyboards.
The way he structures the constraints is using a custom implementation of UIView, that way your view code is separated from the ViewController. Then, in the viewDidLoad method you can instantiate your implementation of UIView with something like self.view = MyView().
I wrote a few apps like this. The major drawbacks are that it can become very difficult to make quick adjustments, and you really need to learn about all the different types of constraints you can use.
Here's a pastebin of some extensions I used when doing this. I hope this helps.
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'm facing with a complex design problem. Due to a hard designed graphic I can't use Apple navigation pattern as UINavigationController or other ones.
This is the app diagram
Black arrow: protocols direction
Blue arrow: parent-child pattern direction
I created this flow because I want to maintain the code inside the single ViewController clear and isolated: I thought about them as modules that they can be used somewhere in other apps.
The RootViewController is the MainVCs position manager. It decides which is the current view-controller that it must be showed and it configures it based on its status (modified by delegate methods).
The single MainVC doesn't know that RootVC exists and it call Root using protocols. The single ChildViewController doesn't know that its MainVC exists and it call the Main using protocols and so on.
Code is clear and much easy to understand, my purpose, but when I have to apply a modify to the skeleton (RootVC) from the ChildViewControllerN, child of the umpteenth ChildViewController, child of the umpteenth MainViewController, I have to propagate the protocol until the RootViewController.
My first question is: is this pattern correct? What do you think about it?
My second question is: is there a limit point where I haven't to use delegate pattern but something like KVO?
ADDING
I read a university lecture about the composite pattern that it says:
A composite object knows its contained components, that is, its children. Should components maintain a reference to their parent component?
Depends on application, but having these references supports the Chain of Responsibility pattern
So, according to the Chain, I can maintain a reference of the parent but I have to declare a custom interface for this kind of reference. However, doing this I will decrease the number of protocols, but the second question still be unanswered
Opinion:
When I go beyond a single level of parent/child relationships, I tend to stop using delegates and move to NSNotification. Frequently, I go directly to NSNotification to reduce dependencies. I prefer that to KVO because it is explicit, whereas KVO is harder to debug as the project progresses.
(Example: what looks like a simple variable assignment on a background thread results in a hard-to-diagnose crash if a listener is deallocated on the main thread between the moment of assignment and the KVO delivery.)
OK, this may sound very basic (especially for someone who has written tens of thousands of Objective-C code), but I've always tried to avoid all this... or just tweak existing solutions. The result? I've never learnt how to do something simple like that.
So, here's my ultra-simple scenario:
I want to create a custom NSView (let's say a simple view with an image and a text in it), which I'll be able to assign in the Interface Builder (take an NSView element and set its class to MYCustomView - that's all - nothing more complicated)
I know I can write an NSView subclass and have it draw all my elements programmatically in drawRect: and all this - but I most definitely don't find any point in that.
What I do want is to simply draw the view in the Interface Builder (in our example, with a "placeholder" image and textfield), be able to use it as the "basis" of our NSView subclass, and also maintain pointers to the two elements in the view so that I can programmatically access them.
I know it's doable - I'm not asking about that. What I need is an ultra-simple walkthrough. Is there anything you can point me to?
Rephrasing the question in a... one-liner:
How can I replace the programmatic approach (seen in like 99.9% of NSView subclasses) in drawRect:, with a layout taken from a XIB?
P.S.
(A) Trust me, it must have been the 100th time I've been reading about NSViewControllers and all these, but not having used them, probably means that I still haven't found the point in using them...
(B) Please, don't shoot me with "what have you tried" questions. In the course of time, I've tried loads of things and at times I've somehow made it. However, it always feels like a crappy, messed up thing I just managed to get working. Nothing more, nothing less. All I want is to know if there is a simple tutorial on the above simple scenario.
(C) If I get an actual explanatory answer to this one, I guarantee I'll re-post it myself. You simply can't believe how many seasoned Cocoa developers have serious trouble dealing with this...
I've always wanted "custom" Storyboard classes as well!
This may not totally answer your question but this is just how we do it now, in iOS: just use container views.
Full extremely long tutorial: https://stackoverflow.com/a/23403979/294884
Everything's a container view in iOS now.
What we do is just have a scene, and then duplicate it: then change the colors or whatever as you describe.
Here's a literal example from the storyboard that was open behind this browser window!
Notice the small class/scene thing, we just copy it. Notice in the example it is slightly customised, just as you say. They are all the same class (it happens to be caled "BookBist") {"bist" == "bouncy list" btw}
Then as I say container views are the secret because, well, it's for exactly this purpose, it's why apple finally introduced "container views".
(BTW on that long container view tutorial. Search down to What if you want (say) a table controller or a page view controller instead of a UIViewController? it's a critical trick when making container views! Ridiculously Apple gives you a "default" VC when you drag in a container view; of course you never want that; in the example at hand I put the small BookBist scenes connected to the container views wherever they are needed.) Example...
Now, I 10000% understand what you are asking and have always wanted to know the answer myself!
For use HALF the answer, is, as I say, "copy the scene" so that works perfectly in modern storyboard. I appreciate that sucks, because what you want is a prefab, like in any game engine such as Unity3D, right? Me too!
But do note that THE OTHER HALF of your answer is certainly "container view magic" - "everything's" a container view now in iOS, indeed Apple finally put them in to make a rational way to do exactly the sort of thing you describe.
Actually this is a simple question with maybe not an answer for a central solution.
I would like a way to monitor in a central way every UIView start-finish loading to get metrics of the application.
I can see that viewWillLoad doesn't exist anyway in the UIViewController class and viewWillAppear is not something that it could serve the purpose.
Is this feasible in any way? I'm thinking of searching every UIView inherited class in the application and inject code somehow, but as I said I will need two methods.
Or maybe inject code to a protocol that already exists in the UIView class?
Any thoughts?
Regards.
If you are only concerned with the loading of the root view of every view controller. You could swizzle -loadView and -viewDidLoad of UIViewController. You could exchange those with methods that add start and end times to a table for each instance that calls them. Keep in mind though, that just the act of measuring it, you are going to slow down the loading.
If you want to track the loading of every view, you could swizzle -initWithFrame on UIView in the same way. In your version of the method you would start tracking before you call the real version and stop tracking once the real method has exited. However, if you have custom views that have their own initializers you will have to come up with a more complex version of that. However I do not recommend doing this. The time it takes to initialize a view is probably less time or at least very close to the amount of time it will take to track it making the timings worthless.