Subclassing UIRefreshControl but still supporting iOS 5.1? - ios

Added a UIRefreshControl to one of my tableviews here, and just used respondsToSelector on the the tableview controller to see if it has the refreshControl property before configuring and adding the UIRefreshControl using NSClassFromString(). Works perfectly and I can continue supporting iOS 5.1 (just without them getting the new control).
However… I want to override the beginRefreshing and endRefreshing methods to dynamically change the tint color of the control. And I figured subclassing UIRefreshControl would be the easiest way of doing this. But how would I do that and still support iOS 5.1?

Actually, assuming your base SDK is at least iOS 6.0, you can subclass UIRefreshControl as long as your deployment target is iOS 3.1 or later. That's because in iOS 3.1, support was added for weakly-linked classes.
With weakly-linked classes, if you send a message to a class that is not present in the running OS, it is the same as messaging nil. Thus, instead of using NSClassFromString(), you can just do this:
if ([UIRefreshControl class]) {
// Use it
}
else {
// Do something else
}
This works even when messaging your own subclass of a weakly-linked class. As Apple's "SDK Compatibility Guide" says,
If you subclass a weakly linked class and the superclass is unavailable, then the subclass also appears unavailable.
So you can just do this:
if ([MyRefreshControl class]) {
MyRefreshControl *control = [[MyRefreshControl alloc] init];
// Do something with the control
}
else {
// Do something else
}
This will work on devices running iOS 5.1 just as well as it works on devices running iOS 6. Your problem is solved.

Related

SWRevealViewController and pauseInteractiveTransition not implemented

I use SWRevealViewController in a lot of my projects. Since updating to Swift 3 with an iOS deployment target of 10.0 or higher, I am now getting a warning Method 'pauseInteractiveTransition' in protocol 'UIViewControllerContextTransitioning' not implemented in SWRevealViewController.m
I see that this is a required for UIViewControllerContextTransitioning but I have no idea how to implement it. So I just added this
- (void)pauseInteractiveTransition {
// not implemented
}
Everything is working fine but I want to know if there is something else I should do.

iOS9 force LTR UINavigationController Push Direction for RTL Languages

I came across this issue while I was working on an old app which had localisation for Arabic language which is written RTL. I noticed that in iOS9, my UINavigationController was showing animation right to left when pushing view controllers. My app views were not ready for it. They had been designed for left to right transition even in Arabic storyboard (because previously in older iOS, UINavigationController only supported LTR transition). Now this RTL animation required that I redesign a lot of assets so I wanted to force it to show LTR animation for all languages. After a bit of research I found the solution.
In iOS9, there is a new constant UISemanticContentAttributeForceLeftToRight for this purpose. The following code fixes the issue and forces left to right animation:
if(([[NSProcessInfo processInfo] respondsToSelector:#selector(isOperatingSystemAtLeastVersion:)]) &&
[[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){9, 0, 0}]) {
[[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
}
We are checking iOS version first to avoid error in iOS version older than 9.
I added the above code in ViewDidLoadof the my base ViewController class (All of my ViewController classes inherit from this one).
Since it is only happening on iOS 9 in your app delegate write the following :
if #available(iOS 9.0, *) {
UIView.appearance().semanticContentAttribute = .ForceLeftToRight
} else {
// Fallback on earlier versions
};

Objective-C: Coding for various iOS versions

I was wondering whether it is possible / how it is possible to code a class so it can be run on different iOS versions in Objective-C. For example the VisualEffectView is only available in iOS8 and after. Is it possible to declare a VisualEffectView if iOS >= 8 and UIView if not? If so can this be done within a header file?
I want to create an alert box to appear on top of a view controller when a save completes or error occurs. Depending on the iOS version it would be nice if a fancy blurry view is used or just a flat UIView.
In an if statement, use NSClassFromString. You'll discover immediately that UIVisualEffectView doesn't exist when it returns nil, and thus you can take one branch if it exists and another if it doesn't:
if (!NSClassFromString(#"UIVisualEffectView")) {
// ... use UIView ...
} else {
// ... use UIViewVisualEffectView ... {
}
As of iOS 5 you can the following syntax.
if ([UIVisualEffectView class]) {
// Create and use a UIVisualEffectView
}
This will occasionally bite you, NSMapTable is available in iOS versions prior to iOS 6, but was only "officially" available in iOS 6. When attempting to use it in iOS 5 there was some sporadic undocumented behavior.
As many have suggested, you can use the NSClassFromString function to find out at run time if the OS version has the class. If it doesn't (that is iOS 7 devices) and you still want live blurring, I'd recommend LiveFrost.

willRotateToInterfaceOrientation not called on iOS8

I'm using the VFR PDF viewer library in my app, where I present it thus:
ReaderDocument *document = [ReaderDocument withDocumentFilePath:pdfFile password:nil];
ReaderViewController *vc = [[ReaderViewController alloc] initWithReaderDocument:document];
[self.navigationController pushViewController:vc animated:YES];
If I run on iOS7, everything works fine.
If I run my app on iOS8, the willRotateToInterfaceOrientation method in ReaderViewController never gets called, so when the device is rotated the document doesn't get reformatted correctly.
However, if I run the demo app that comes with the library on iOS8, the willRotateToInterfaceOrientation in ReaderViewController does get called, which leads me to believe the library is ok, and I'm doing something wrong (or neglecting to do something) in my app.
I'm rather puzzled at this behaviour. Why doesn't willRotateToInterfaceOrientation get called in my app on iOS8, but it does under the other variations? How can I try to track this down?
I finally managed to resolve my problem; here is what the issue was in case anyone else has the same problem.
My ReaderViewController was being presented from a class that had implemented viewWillTransitionToSize:withTransitionCoordinator:, so the deprecated methods on child view controllers weren't being called.
Also in that implementation it wasn't calling
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]
and so the viewWillTransitionToSize:withTransitionCoordinator: method of all child view controllers wasn't being called either.
The fix was to add a call to
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]
into the parent VC's viewWillTransitionToSize:withTransitionCoordinator: method, subclass ReaderViewController, then add a viewWillTransitionToSize:withTransitionCoordinator: to my subclass to call the appropriate methods in ReaderViewController.
Simply because willRotateToInterfaceOrientation is no more called in iOS8, it is deprecated.
If the new rotation methods are not implemented, and a project is
compiled with the iOS 8 SDK, the view controllers -will not receive
calls- to the deprecated rotation methods.
A similar question to yours can be found here
Citation of #mluisbrown :
The rotation methods are deprecated in the iOS 8 SDK. This will have
no effect at all on apps built with the iOS 7 SDK, even running in iOS
8 and probably several future versions of iOS.
I struggled a bit with some kind of a similar problem to yours. I tried following Apple recommendation to use viewWillTransitionToSize, which in my case did not solve my problem because this only gets triggered on changes from regular to compact for example an not on rotation.
viewWillTransitionToSize:withTransitionCoordinator: to make
interface-based adjustments.
Which is detailed in apple documentation
Also a video of WWDC 2014 explains this but I can't remember which video it was. Perhaps the one on What's new in Cocoa touch or the one on View Controller Advancements in iOS 8.
EDIT
Note that in my case viewWillTransitionToSize, as explained, was not called because I wasn't changing from regular to compact so there was no size transition, strictly speaking for Apple.
The only solution I fount was to handle this manually in the viewDidLayoutSubviews of the corresponding view controller.
In my case I wanted to keep track of the top cell displayed in a tableview with autolayout. As it wasn't tracked automatically by the system, I had to check that manually and scroll manually to the adequate cell on rotation. That's why I did it that way. It's quite "heavy" but works in my case.
I would also be interested if anyone has an easier solution.

UITableView dequeueReusableHeaderFooterViewWithIdentifier returns nil with VoiceOver on iOS 7

I am having some trouble with VoiceOver turned on starting in iOS 7. I did register an instance of UITableViewHeaderFooterView child class inside viewDidLoad but when I am dequeque-ing it with -[tableView dequeueReusableHeaderFooterViewWithIdentifier:] it is always returning nil object.
The issue started to appear on iOS 7.0. It was not there on the previous version and certainly it works fine if it runs perfectly without VoiceOver on both 6.0 and 7.0
I could just not having a custom header instead, or instantiate a new object when dequeueReusableHeaderFooterViewWithIdentifier: returns nil. But I was wondering whether there is a known issue regarding this.
Cheers,
You can use below method to create custom UITableViewHeaderFooterView
(void)registerClass:(Class)aClass forHeaderFooterViewReuseIdentifier:(NSString *)identifier

Resources