UIViewController - orientation changes don't get reported - uiview

In my UIViewController subclasses, I impliment - (void)didAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation, but it never gets called, although I have correctly implemented - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation and my views do get rotated.

You must also implement willAnimateFirstHalfOfRotationToInterfaceOrientation for the did... to get called. I suspect the framework first tries to call the will... and if it doesn't find it implemented it assumes you didn't implement the did... either, and so never calls it.

Related

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.

Category is implementing a method which also be implemented in primary class : `viewWillAppear:`

I'm trying to category UIViewController to override viewWillAppear:. But getting this warning.
Category is implementing a method which also be implemented in primary
class
#implementation UIViewController (ViewWillAppearCategory)
-(void)viewWillAppear:(BOOL)animated
{
//.........
}
#end
I want to do some stuff during view appear in all screen, So I don't want to touch in all screen. that's why, go with category.
I may implement some method in sub class and I can call that method in all VC(all Screen). But I don't want this. It automatically invoke in view will appear call. Is this any idea to do this or did any mistake in above?
Note: This code will only appear in development phase for some testing purpose. So I'll remove this code when go with app store. So It should be easier task during removal, that is I won't touch all screen. I won't keep this code during submission to app store.
In such cases you must try Method Swizzling, a very nice formed concept which allows you to change the implementation of an existing selector.
For more details and code please visit the link below.
http://nshipster.com/method-swizzling/
categories are for adding new methods, not overriding existing ones. Maybe make a subclass of UIViewController, say, MyUIViewController, with this code:
-(void) viewWillAppear:(BOOL) animated {
// do your "category" stuff
}
then make all your other UIViewControllers subclasses of MyUIViewController with this code:
-(void) viewWillAppear:(BOOL) animated {
[super viewWillAppear:animated];
// rest of code for this class
}
I understand the reasons why you want to have a simple solution to test something on all screens and remove it easily, however:
You can not call super in a category, and not calling [super viewWillAppear:] may have unexpected results depending on the class and its particular implementation.
Swizzling methods is a hack and as you'll remove it from your final version, your testing version becomes useless as it may behave very differently.
On the other hand creating a UIViewController superclass where you properly override viewWillAppear: is not that complicated:
The code will belong only to a single class. No need to repeat/maintain code for every "screen".
You only need to change the other controllers' superclass and Nibs or Storyboards references once.
You can keep the superclass for both testing and release and the behavior will be similar.
You can do so many more things in a superclass than in a category.
Ultimately it would be interesting to know what are you trying to achieve. You could probably achieve similar things by implementing a UINavigationControllerDelegate and keep track of controllers getting pushed and popped.
As for viewWillAppear documentation:
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.
Again, you can't do that from a category.
As you are saying the code is going to be executed only in debug mode. Then why do you worry about warnings let the warning come you continue your work when it comes to release you remove your Category.
If you don't even need to see the warning your go with your same answer like
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
-(void)viewWillAppear:(BOOL)animated
{
NSLog(#"I get callback here too");
}
#pragma clang diagnostic pop
But I would say to go for subclassing because removing the existing class is also not that hard in XCode tool.
What you want to achieve defeats the purpose of a Category. However, there's another way aside from subclassing UIViewController but you have to touch the viewWillAppear method for each controller.
//UIViewController+CustomCategory.h
#interface UIViewConctroller (CustomCategory)
- (void)performCustomization;
#end
//UIViewController+CustomCategory.m
#implementation UIViewController (CustomCategory)
- (void)performCustomization {
// Do custom stuff…
}
#end
Then in each controller
//MYViewController.m
#import "UIViewController+CustomCategory.h"
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self performCustomization];
}

Weak Event Pattern in MonoTouch

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.

Ideal place to put a method after orientation has changed

I have an issue and here how it goes,
I have a view with a subview, the subview is loaded conditionally, only if the parent view is setHidden property is set to YES;
something like [parentView setHidden:YES] and if([parentView isHidden]),
I want to call a method when the orientation changes and that is the cited snippet above, but I have observed that the method shouldAutorotateToInterfaceOrientation is called 4 times during loading and 2 times during runtime, since the method is called more than once, how can I possibly implement a method call ideally since apple's existing method doesn't seem to give me the intuitiveness to put my custom method call with the existing method.
If I would hack this thing, it is possible, but somebody might have a better idea before resorting to things that in the future would just cause me more trouble than benefit.
TIA
Have you tried with
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
// check here for your desired rotation
}

Calling the delegate methods

Still I couldn't understand completely how these delegate methods are getting called.
I have UIViewController,UITextFieldDelegate in one class which will call its delegate methods without specifying like textField.delegate = self;
But for some different purposes like UIWebViewDelegate we are supposed to enter like webView.delegate = self; and it seems like it is calling its delegate methods. Perfect.
But now I am facing a problem. I am using CLLocationManagerDelegate and also CALayer in same class. For both I am giving location.delegate =self; and layer.delegate =self; At some point both are conflicting each other and only one of the thing is working either CLLocationManagerDelegate or CALayer. The other thing is getting stopped. I don't why it so happens like this? Any reason? How can we overcome this. Even I planned to use some other frameWork, say UIWebView . I will face same problem for those delegate methods also. Can you tell me why it is working in that way ?
The classes that will call its delegates without you specifying them have default implementations, which means that they already know what to do, and will only change their behavior if you override these methods.
Setting 2 or more classes to the same delegate should not interfere with each other (unless for a very weird reason in where the method is named the same in both custom classes).
Your problem is most likely the fact that you havent implemented those methods or are using those classes wrong.
For example, Location manager requires you to create an instance, configure it and START running updates. The most common method for a delegate of this type is the "did update location" (or something like that). Which you have to implement if you want to be informed of every time a new location is received. Otherwise you have to read the location manually whenever you desire.
As a suggestion, every time you set a delegate for an object, you have to do the object.delegate = self; thing. And you probably noticed that you will get a warning until you specify in the header that it conforms to that protocol: for example.
Just control click the UITextFieldDelegate word.
Look for the methods under #required, THOSE you have to always implement. the #optional have default implementations so unless you wanna change the behavior its not needed to implement them.

Resources