Storyboards + generics = inline initializers not called? - ios

I'm looking for an explanation of why the following prints false when run on iOS. The view controller is instantiated from a dead-simple Storyboard which just contains a single table view.
I'm using the preloading trick suggested by https://stackoverflow.com/a/33658528/1919412 to allow Interface Builder to find the MyTableViewController class. I'm sure that has something to do with the problem, but I'd like to better understand what's going on.
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
// If we don't create this dummy instance before our real view controller gets loaded from storyboard, we get this error:
// "Unknown class _TtC21ViewControllerInitBug21MyTableViewController in Interface Builder file."
// See: https://stackoverflow.com/a/33658528/1919412
let foo = MyTableViewController()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
return true
}
}
class Foo<T>:UITableViewController {
init() {
super.init(style:.Plain)
}
}
class MyTableViewController:Foo<String> {
private var foo = true
override func viewDidLoad() {
super.viewDidLoad()
print(self.foo)
}
}

Related

issue while accessing global func in app delegate

I am new to swift and i created one swift file with name mySession and in that file i am storing login data like below
Store Login Data
func setLoginData (data:Data) {
let preferences = UserDefaults.standard
let Key_Login = "Login"
preferences.set(data, forKey: Key_Login)
preferences.synchronize()
}
and second func for use that stored data
Get Data
func getLoginData ()->Data {
let preferences = UserDefaults.standard
let Key_Login = "Login"
if preferences.object(forKey: Key_Login) == nil {
return data
} else {
return preferences.data(forKey: Key_Login)!
}
}
So now my question is that i want to use getLoginData func in my app delegate to check user is logged in or not so not able to under stand how to use that func in app delegate
You should encapsulate these methods inside a class and use an instance of that class inside AppDelegate
class MySession {
func setLogin(_ data: Data){...}
func getLoginData() -> Data {...}
}
At the call site, instantiate MySession and use your methods to do what's needed.
class AppDelegate {
//...
let sessionHandler = MySession()
sessionHandler.getLoginData()
}
Sidenote, make sure you're using proper Swift 4 naming conventions.
First Import the file name in AppDelegate
Import mySession
Then just call the method in your desired function.
setLoginData(data:<your Data>)
For example.If you want to use it in didFinishLaunchingWithOptions method, follow this
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
DefaultNetworkManager.appsConfigSetup()
window = UIWindow(frame: UIScreen.main.bounds)
setupApplication()
setLoginData(data: <Your Data>)
return true
}

Chartboost Delegate not working in swift

Desired : I want to do something when Delegates method call Observed :Delegates method not calling Ad's show on the screen successfully
Error
code:Chartboost.delegate=self
Error: Type 'Chartboost' has no member 'delegate'
AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Chartboost.start(withAppId: "4f21c409cd1cb2fb7000001b", appSignature: "92e2de2fd7070327bdeb54c15a5295309c6fcd2d", delegate: nil)
return true
}
ViewController Code
class ViewController: UIViewController,GADBannerViewDelegate, GADInterstitialDelegate,GADRewardBasedVideoAdDelegate,IMBannerDelegate, IMInterstitialDelegate ,ChartboostDelegate{
#IBAction func Vedio(_ sender: Any) {
Chartboost.showRewardedVideo(CBLocationMainMenu)
}
#IBAction func LoadFullAd(_ sender: Any) {
Chartboost.showInterstitial(CBLocationHomeScreen)
}
private func shouldDisplayRewardedVideo(_ location: CBLocation) -> Bool {
return true
}
private func shouldRequestInterstitial(_ location: CBLocation) -> Bool {
return true
}
}
A had to set the delegate as self with Chartboost.setDelegate(self)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
Chartboost.start(withAppId: "4f21c409cd1cb2fb7000001b", appSignature: "92e2de2fd7070327bdeb54c15a5295309c6fcd2d", delegate:self as ChartboostDelegate)
Chartboost.setDelegate(self as ChartboostDelegate)
return true
}
After looking at how to properly convert Objective-C methods in Swift, I added the underscore (_), which changed the function to:
func shouldDisplayRewardedVideo(_ location: CBLocation) -> Bool
{
return true
}
func shouldRequestInterstitial(_ location: CBLocation) -> Bool {
return true
}
XCode then gave me a hint that I was close to the delegate method, but needed to change the type of location and I ended up with
func shouldDisplayRewardedVideo(_ location: String) -> Bool
{
return true
}
func shouldRequestInterstitial(_ location: String) -> Bool {
return true
}
If the delegate is set to nil, the class that calls the delegate's methods (in this case Chartboost) will not be able to make the delegate's method calls. You should set the delegate to the 'self' of the class where you have implemented the delegate methods expected by Chartboost.
In the example above, you could set the Chartboost delegate to the 'self' of the ViewController.
For example, inside of ViewController, you have already declared the 'ChartboostDelegate' in the class signature. When you want to turn on the Chartboost delegate methods, assign the ViewController's 'self' to the Chartboost delegate using something like:
Chartboost.delegate = self
In the case of Chartboost, it looks like the author made the delegate private, so it can be set in the ViewController using:
Chartboost.start(withAppId: "some uid", appSignature: "some other uid", delegate: self)
or, as later found out:
Chartboost.setDelegate(self)
(It can also be set in the AppDelegate class by locating the ViewController instance in the storyboard. Not a great fit in this case.)
If you're having problems generating the delegate method's call signature stubs (the method calls expected by the delegate), XCode will autogenerate them for you. Just click on the error message found next to your class declaration:
Type '<your class implementing the delegate methods>' does not conform to protocol '<the delegate protocol to implement>'
More detail about the error will appear. Click the 'Fix' button and XCode will autogenerate the method stubs for you.

Typhoon Dependency Injection and Swift 3: Appdelegate isn't AnyObject

This code works with Typhoon Dependency Injection library (Obj-C) in Swift 2.3 but doesn't in Swift 3:
AppDelegate:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var rootViewController: RootViewController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = self.rootViewController
self.window?.makeKeyAndVisible()
return true
}
...
}
Application Assembly:
public class ApplicationAssembly: TyphoonAssembly {
public dynamic func config() -> AnyObject {
return TyphoonDefinition.withConfigName("Configuration.plist")
}
public dynamic func appDelegate() -> AnyObject {
return TyphoonDefinition.withClass(AppDelegate.self) {
(definition) in
definition!.injectProperty(#selector(ApplicationAssembly.rootViewController), with: self.rootViewController())
}
}
...
}
However the following error is displayed in ApplicationAssembly for any Swift 3 file expected to return 'AnyObject':
"No 'withClass' candidates produce the expected contextual result type 'AnyObject'
Might anyone have an insight into the incompatibility of the Obj-c Typhoon code base with Swift 3?
Screen capture of error line
You may want to switch the return type from AnyObject to Any.
The withClass function returns an id type in Objective-C, see the source code:
+ (id)withClass:(Class)clazz block:(TyphoonBlockDefinitionInitializerBlock)block;
The id type used to be mapped to AnyObject in Swift 2, but in Swift 3 it's mapped to Any for increased flexibility. You can read more about this change here.

Transform UIApplicationDelegate methods into RxSwift Observables

In RxSwift / RxCocoa you can create a reactive wrapper for a delegate (e.g. UIScrollViewDelegate or CLLocationManagerDelegate) to enable Rx observable sequences for certain delegate methods.
I am trying to implement this for the UIApplicationDelegate method applicationDidBecomeActive:
What I tried so far is pretty straightforward and similar to the DelegateProxy subclasses that are included in RxCocoa.
I created my DelegateProxy subclass:
class RxUIApplicationDelegateProxy: DelegateProxy, UIApplicationDelegate, DelegateProxyType {
static func currentDelegateFor(object: AnyObject) -> AnyObject? {
let application: UIApplication = object as! UIApplication
return application.delegate
}
static func setCurrentDelegate(delegate: AnyObject?, toObject object: AnyObject) {
let application: UIApplication = object as! UIApplication
application.delegate = delegate as? UIApplicationDelegate
}
}
And an Rx extension for UIApplication:
extension UIApplication {
public var rx_delegate: DelegateProxy {
return proxyForObject(RxUIApplicationDelegateProxy.self, self)
}
public var rx_applicationDidBecomeActive: Observable<Void> {
return rx_delegate.observe("applicationDidBecomeActive:")
.map { _ in
return
}
}
}
In my AppDelegate I subscribe to the observable:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// the usual setup
// and then:
application.rx_applicationDidBecomeActive
.subscribeNext { _ in
print("Active!")
}
.addDisposableTo(disposeBag)
return true
}
When I start my app "Active!" gets printed and then I get the following crash in RxCocoa's _RXDelegateProxy_ class:
Does anybody have an idea what the problem might be? Or has anybody successfully implemented something like rx_applicationDidBecomeActive?
It looks like a really tricky issue with RxSwift and memory management.
The default implementation of DelegateProxyType sets an instance of a delegate proxy (in this case, RxUIApplicationDelegateProxy) to the delegate of UIApplication.
It also stores the original AppDelegate as a property called forwardToDelegate so all the delegate methods can still be passed to it.
The problem is that, when the new app delegate is set:
application.delegate = delegate as? UIApplicationDelegate
the original one is deallocated! You can check it by overriding deinit in AppDelegate. The reasons are explained in this answer. And because the property forwardToDelegate is of type assign, your app crashes as the property points to a deallocated object.
I have found a workaround for that. I'm not really sure if it is a recommended way, so be warned. You can override a method from DelegateProxyType in RxUIApplicationDelegateProxy:
override func setForwardToDelegate(delegate: AnyObject?, retainDelegate: Bool) {
super.setForwardToDelegate(delegate, retainDelegate: true)
}
In normal circumstances, you don't want to retain the delegate as it leads to a retain cycle. But in this special case, this is not a problem: your UIApplication object will exist the entire time while your application is alive anyway.

Swift Framework Class to Swift Application

Getting problem with adding my Swift Framework to Test Swift Application.
What i have:
Framework class code, Target Called 'Project':
public let Instance = Library()
public class Library {
public class var sharedInstance: Library {
return Instance
}
/* SOME CODE */
}
Than i build it and add Project.framework to Test Swift Application
Usage:
import Project
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
/* NOT WORKING
ERROR: Use of Unresolved Identifier 'Instance' */
Instance.Setup("d573732b9f8b478d",apiKey: "3XmdIY=", enablePush: true)
/* NOT WORKING TOO
ERROR: Use of Unresolved Identifier 'Library' */
let lib = Library()
return true
}
Functions public, DeviredData deleted, what i'm doing wrong?
Answer was very easy:
Adding constructor function
public init(){
}
Problem solved.
Yes, making public constructor will help you, as per my knowledge default constructor has internal scope. It works for me.
public override init() {
}

Resources