A way to monitor any UIView load - ios

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.

Related

KVO within Swift Extension

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.

Is it a MUST for viewWillAppear to have [super viewWillAppear] method as well

I placed my code for iAd/AdMob ads in...
-(void)viewWillAppear:(BOOL)animated{}
Ads work perfectly fine the way I have them now on all iOS devices.
When I connected my iPhone to Xcode and clicked on Product -->Analyze a message states...
The viewWillAppear:instance method in UIViewController subclass 'iPhoneSIX' is missing a [super viewWillAppear:] call
I just accidentally stumbled upon this Product-->Analyze thing. Do I really need to add [super viewWillAppear] even though everything works perfectly fine on all devices as it currently is. Will Apple reject my app if I don't pay attention to the Product-->Analyze issue navigator?
Also, what does ...
[super viewWillAppear:YES];
What does calling this do?
According to Apple: (emphasis mine)
This method is called before the receiver's view is about to be
added to a view hierarchy and before any animations are configured for
showing the view. You can override this method to perform custom tasks
associated with displaying the view. For example, you might use this
method to change the orientation or style of the status bar to
coordinate with the orientation or style of the view being presented.
If you override this method, you must call super at some point in your
implementation.
Apple doesn't gets that specific when deciding to Accept or Reject your app. It only follows the guidelines, which doesn't get that much into the weeds of your specific methods.
Calling [super viewWillAppear:YES] is a best practice, and I would recommend it. Always including super ensures that any code in the super classes get called before executing any additional code. So if you or someone else coded a super class that expected some code to be executed, you are guaranteed to still execute it, rather than just overwriting the whole method in the subclass.
Say you have a view controller of type MyViewController which is a subclass of UIViewController. Then say you have another view controller of type MyOtherViewController, which is a subclass of MyViewController. Say you're coding now some things in viewWillAppear in MyOtherViewController. If you call super first, it will call viewWillAppear in MyViewController before executing any code. If viewWillAppear in MyViewController calls super first, then it will call viewWillAppear in UIViewController before executing any code.
I'm quite certain Apple will not reject your app for failing to call super on an overridden method, primarily because there are cases where you may specifically want to avoid calling super.
That said, as Josh Gafni mentions it is definitely a best practice to do so, unless you have a very good reason for not. Also bear in mind some view controller subclasses (can't recall specifically which ones, but maybe UICollectionViewController) will only work properly if their view lifecycle methods get called appropriately, so not calling super can definitely break some classes (sometimes in subtle ways you may not realize).
Therefore my suggestion is add the call to super (generally as the first line in the method) and see if things continue to work fine. If not, spend a bit of time trying to understand what is happening differently and see if you can solve it in a different way. In general you should always (as a force of habit) provide calls to super on any view lifecycle methods you override whenever possible.

how to detect interface changes on iOS application

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.

Singleton-Like UIView Access?

I have a UIView I need to access the properties of from all around my app. I know you can't create a Singleton around a UIView object, so what might be a good way of doing similar?
E.g. The view has a label. From any view controller in my app I want to be able to change the text of this view (sitting in a parent view controller).
Thanks.
EDIT:
Success! Using KVO to track changes in my Singleton object worked a charm, and a very simple solution.
I think what you’re trying to do violates the separation of concerns of the MVC pattern: The only thing that should interact with a view is its controller. In your case, you should probably be creating a model that is watched by your view controller (maybe through key–value observing), and then the controller can propagate the necessary changes to your view.
If you know (read: you really know for now and forever!) that there will be at most one instance of that view alive at one point in time, you can just use a global variable to store that. Or use a class property on that view - which is as close as being a singleton as possible.
Or you might just fix your design, which has proven to be the better choice in every case I can remember. :) Just add some forward and backward references in your classes (and stick to MVC principle). It takes much less time to implement that worrying about those awkward workaround, and it will pay of rather sooner than later.

How to resolve memory crash

I'm creating an application which features having multiple animations.
There are 50 pages and on each page there is a different animation and each animation uses many images.
I'm using UIPresentModelViewController for presenting the views and
am changing images using NSTimer.
When I swipe continuously the application crashes with this message:-
Program received signal: “0”.
Data Formatters temporarily unavailable, will re-try after a 'continue'.
(Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
I searched a lot but couldn't find any proper solutions to this issue.
Just check within your code that you are making some mistake by adding new view every time but forgot to release it...
You need to look at (and perhaps post) the stack trace when you crash. And the code that changes the image. This sounds like memory bloat (not a true leak in that someone is still referring to memory). The Analyze menu item might catch something (and you should definitely run it), but you may need to run the Allocation instrument and look at heap checks. See http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/ for more.
This sounds like a stack overflow to me. In the "Other C Flags" section of the project's C/C++ language settings add a flag for "-fstack-check" and see if that turns up any unwanted recursion.
Signal 0 is usually due to memory low as the app using too much memory. Check whether memory warning method is called or not.
The data formatter thingy failed to load might be due to there's not enough memory to load it..
50 views like you describe sounds like a big memory hog. So I suspect memory management is unloading some views. Then when your program needs the views, they are not there and your program crashes. The error message doesn't quite fit this, but it may not be accurately telling you what the problem is.
Consider the following possible scenario, and see if it fits how you coded this program.
In order for the OS to manage memory, it can unload views and reload them as needed. When this is done, the methods viewDidUnload, loadView, and viewDidLoad are called.
viewDidUnload:
This method is called as a counterpart to the viewDidLoad method. It is called during low-memory conditions when the view controller needs to release its view and any objects associated with that view to free up memory. Because view controllers often store references to views and other view-related objects, you should use this method to relinquish ownership in those objects so that the memory for them can be reclaimed. You should do this only for objects that you can easily recreate later, either in your viewDidLoad method or from other parts of your application. You should not use this method to release user data or any other information that cannot be easily recreated.
loadView:
The view controller calls this method when the view property is requested but is currently nil. If you create your views manually, you must override this method and use it to create your views. If you use Interface Builder to create your views and initialize the view controller—that is, you initialize the view using the initWithNibName:bundle: method, set the nibName and nibBundle properties directly, or create both your views and view controller in Interface Builder—then you must not override this method.
Check the UIView Class Reference --
viewDidLoad:
This method is called after the view controller has loaded its associated views into memory. This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method. This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
You may have inadvertently initialized these views in your init methods rather than in your loadView methods. If you did this, then when the OS unloads a view (you will see viewDidUnload is called) the memory associated with the view and all subviews (all of the images and animations) will be unloaded. This saves memory, but when you need one of those unloaded views to reappear, loadView will be called first if the view had been previously unloaded. If your view setup is done in the init methods rather than in loadView, then the view will not be setup again. But if the view setup is done in loadView method, it can be recovered after memory management unloads it.
There is one and easy way to find out leaks that is hard to find via leaks instruments and so on - Zombies analyser. It shows every unlinked memory in your program, and you can easily detect leaks and optimize code in minutes.
If you're using lots of images for a single animation you're doing it wrong. You should have one, or several very large images and then just show a portion of that image. This way you can load very few images, but have the same affect of having many images.
Look into cocos2d or other frameworks that are popular for making games, as they will be much more efficient for animations than just UIKit.
Find out the reason for memory crash using instrument tool and then refactor the code with best practises with recommended design pattern. There is no unique solution for this. Thanks.

Resources