Just wanted to know if overriding UITabBarController would get my app rejected? Is it allowed by Apple??
Any of you have submitted an app by overriding UITabBarController??
It won't get your app rejected. In general it's fine to subclass UIKit classes, or any Cocoa Touch class. Apple docs actually recommend subclassing for UITableViewCell if you can't get by just using its properties. What gets you rejected is calling private APIs -- the ones that exist if you use reflection to inspect UIKit objects, but aren't in the reference material.
However, look closely at the delegate spec for what you're subclassing. If you can use a partner object better, that's going to produce more reusable code. In other words, when the SDK gets updated and the API class changes, your code is more likely to still work if you supply a delegate rather than subclassing.
Related
Background: In order to make web requests to an API endpoint, I need to scrape a website and retrieve a token every 25-30 seconds. I'm doing this with a WKWebView and injecting some custom JavaScript using WKUserScript to retrieve AJAX response headers containing the token. Please focus on the question specifically and not on this background information - I'm attempting this entirely for my own educational purposes.
Goal
I will have different 'model' classes, or even just other UIViewControllers, that may need to call the shared UIViewController to retrieve this token to make an authenticated request.
Maybe I might abstract this into one "Sdk" class. Regardless, this 'model' SDK class could be instantiated and used by any other ViewController.
More info
I would like to be able to call the UIViewController of the WKWebView and retrieve some data. Unless I re-create it every 25 seconds, I need to run it in the background or share it. I would like to be able to run a UIViewController 'in the background' and receive some information from it once WKWebView has done it's thing.
I know there are multiple ways of communicating with another ViewController including delegation and segueing. However, I'm not sure that these help me keep the view containing the WKWebView existing in the background so I can call it's ViewController and have it re-perform the scrape. Delegation may work for normal code, but what about one that must have the view existing? Would I have to re-create this WKWebView dynamically each time a different model, or view controller, were to try and get this token?
One post suggests utilising ContainerViewControllers. From this, I gather that in the 'master' ViewController (the one containing the other ones), I could place the hidden WKWebView to do it's thing and communicate to the child view controllers that way via delegation.
Another post suggests using AppDelegate and making it a shared service. I'm completely against using a Singleton as it is widely considered an anti-pattern. There must be another way, even if a little more complex, that helps me do what I want without resorting to this 'cheat'.
This post talks about communicating between multiple ViewControllers, but I can't figure out how this would be useful when something needs to stay running and executing things.
How about any other ways to do this? Run something in a background thread with a strong pointer so it doesn't get discarded? I'm using Xcode 9.2, Swift 4, and iOS 11. As I'm very new to iOS programming, any small code examples on this would be appreciated.
Unfortunately, WKWebView must be in the view hierarchy to use it. You must have added it as a sub view of an on-screen view controller.
This was fine for me. I added this off-screen so it was not visible. Hidden attribute might have worked as well. Either way you must call addSubview with it to make it work.
There are some other questions and answers here which verify this.
Here is a way if you don't wish to use a singleton.
1- In the DidFinishlaunchingWithOptions, Make a timer that runs in the background and call a method inside the app delegate Called FetchNewToken.
2- In FetchNewToken, make the call needed and retrieve the new token (you can use alamofire or any 3rd library to make the call easier for you).
Up on successfully retrieving the token, save it in NSUserDefaults under the name upToDateToken
You can access this token anywhere from the application using NSUserDefaults and it will always be up to date.
I'm developing an app which handles some downloads in the background. I move the file to the documents directory and save it under the original name (using downloadTask.originalRequest?.URL!.pathExtension). So far so good.
Using
URLSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)
I can print out the progress in the console while downloading. But this doesn't help me if I'm using the App on the phone. What I'm expecting to do is to call a function to update a progress bar from here within my View that was initialising the download. But I have no idea how to call it.
Does anybody know how I can find out from which UIViewController (actually most of the time it will be a TableCellViewController) I started the download and how to send the progress to a function of that ViewController?
I 'd like to tell you a good tutorial about this question. NSURLSession Tutorial
Delegates are often used in the following situations
When a class needs to communicate some information to another class
When a class wants to allow another class to customize it
The classes don't need to know anything about each other beforehand except that the delegate class conforms to the required protocol.
I the following article you can see how to create a delegate in objective-C and Swift 2.0.
How do I create delegates in Objective-C?
In the past I would do:
MainViewController pushes ProfileViewController
In willPerformSegue, give the target ProfileViewController access to a profile instance
Also set target delegate to self
ProfileViewController allows the user to edit their profile
User presses save
ProfileViewController calls sends message didSave to delegate and pops out
MainViewController handles the didSave by saving the model to disk
All of this still works in Swift. My question is: is this still the favored way to handle inter-VC communication in the Swift era?
Yes, it is. Or rather you can do it the same way.
Swift is just another language, which uses the same libraries.
Things you describe related to those libraries, the notion of UIViewController is defined within them, so everything is done the same way.
The delegate pattern works well, but it's not the only way to communicate between controllers, and it can't be "best" in all cases. The best way depends on the task you're trying to solve, not the language you use.
My question is: is this still the favored way to handle inter-VC communication in the Swift era?
With the caveat that the method name is -performSegueWithIdentifier:sender:, that's fine way to do it, and as far as I know it's still fine under Swift. Apple didn't make any announcement at WWDC 2015 that things have changed in this respect, and the UIViewController interface doesn't suggest any more compelling ways to configure a view controller during a segue.
MainViewController handles the didSave by saving the model to disk
That's also fine, since MainViewController is ProfileViewController's delegate, and it sounds like ProfileViewController isn't aware of the entire model. In other circumstances, it might make sense for a view controller to use the model directly, and for the model to handle saving. But that's a design issue, not a Swift vs. Objective-C issue.
Is their a safe way to determine if class / method you are accessing is not restricted at runtime ?
Or
do these classes have some property which you check and safely avoid using them?
E.g. UINavigationTransitionView or UITransitionView are accessible but undocumented, hence I assume you are not allowed to use them.
Uhm, as the name implies, any method or class not documented in the public Apple documentation or in the SDK header files is considered private API and should not be used for AppStore submissions.
Note, that sometimes you may find yourself accessing public methods on private classes. This is generally acceptable, but it depends on your use.
There are also cases, where Apple has opened API and made public retroactively, meaning you can use a method for current SDK as well as call it on previous versions of iOS safely. Examples of this include NSArray's firstObject and NSDatas base64 API.
There's no way to check programmatically at run-time. In order to know whether you're accessing a private API, you'd need to know which SDK the app was built with, and then you'd need to check every function or method call against the headers from that SDK. Since iPhones don't generally have an SDK installed, there's no way to do that check at runtime.
If you use constructions like:
Class transitionViewClass = NSClassFromString("UITransitionView");
then it's impossible to determine it's access level (public or private) at runtime.
It's better to use direct access to classes/methods:
Class transitionViewClass = [UITransitionView class];
In this case compiler that Xcode uses will show warnings/errors that this class is undeclared:
Semantic issue: Use of undeclared identifier 'UITransitionView'
I'm fairly new to Objective-C and am confused on what falls under the unbrella of a "private API" that could cause Apple to reject my app. Does this include adding methods to existing classes? For example, I found some code on stackoverflow to recolor the tab bar icons for UITabBars with this extension to the UITabBarItem class. Is this considered a "private API"? If not, what does?
#interface UITabBar (ColorExtensions)
- (void)recolorItemsWithImage:(UIImage *)image shadowColor:(UIColor *)shadowColor shadowOffset:(CGSize)shadowOffset shadowBlur:(CGFloat)shadowBlur;
#end
No, categories added by user code are not "private." Private APIs are Apple's internal APIs, which are undocumented. Methods are private if they aren't in the header files and aren't in the developer documentation. (As a rule of thumb, if you don't get any compiler warnings, you aren't using private APIs.)
The above is probably an Objective-C category that extends the UITabBar class with new methods. This is perfectly kosher. You can even overwrite existing methods with categories, although this isn't recommended.
In general, private methods will often have underscores in front of them. You also don't want to use private classes that Apple reserves for large UI objects, such as the private components within a UIWebView. You don't want to use these or your app will get rejected.
Anything that you see in a header file in the Frameworks in your project is "public" and usable. It's a good idea to thumb through the header if you really want to know everything about the class, anyway.