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.
Related
I'm trying to replicate Firebase Analytics behaviour, which automatically fire screen events whenever ViewController screen get's changed with another.
Though I'm able to find currently visible ViewController using :
UIApplication.shared.windows.first?.rootViewController?.presentedViewController
But I need some way to get notified for any change in rootViewController. I tried to observe this rootViewController using KVO, but I don't get any callback. I found that KVO only works on NSObject with dynamic properties.
Is there any way I could receive callback for change in ViewController? Since this will be a library project, I couldn't make changes in main code to support the feature.
Following solution worked for me:-
import Foundation
import UIKit
public extension UIViewController {
#objc dynamic func _tracked_viewWillAppear(_ animated: Bool) {
UserActivityTracker.startTracking(viewController: self)
}
static func swizzle() {
//Make sure This isn't a subclass of UIViewController,
//So that It applies to all UIViewController childs
if self != UIViewController.self {
return
}
let _: () = {
let originalSelector =
#selector(UIViewController.viewWillAppear(_:))
let swizzledSelector =
#selector(UIViewController._tracked_viewWillAppear(_:))
let originalMethod =
class_getInstanceMethod(self, originalSelector)
let swizzledMethod =
class_getInstanceMethod(self, swizzledSelector)
method_exchangeImplementations(originalMethod!, swizzledMethod!);
}()
}
}
In above code _tracked_viewWillAppear() is my custom function which I want to call my implementation before actual implementation called.
Then in AppDeligate class, call UIViewController.swizzle() method, as follows:-
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIViewController.swizzle()
return true
}
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
}
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.
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)
}
}
I'm implementing RAC with MVVM pattern in my project and now I came into a doubt.
I have many calls to the server, but all of them are associated to an UIButton and handled in my ViewModel; now I need to make a call to the server when the UIViewController is loaded. Before MVVM I just created a signal in the viewDidLoad method an voilá!, but I'm not sure if is ok to put this in the ViewController.
Now I don't know how to bind a RACSignal to an event in my ViewController, and worst of that, I'm not sure if that is the way following the MVVM pattern.
What I'm doing right now when I make a call to server coming from a user action(from a UIButton) is this:
ViewController*
self.someButton.rac_command = viewModel.executeSomeAction
//On success:
self.viewModel.executeLoginCompleted.skip(1).subscribeNextAs {
(isExecuting: Bool) -> () in
//Do something
}
//On error:
self.viewModel.executeSomeActionError.subscribeNextAs {
(error: NSError) -> () in
//Dd something
}
ViewModel*
var executeSomeAction: RACCommand?
var executeSomeActionError: RACSignal!
var executeLoginCompleted: RACSignal
executeSomeAction = RACCommand(enabled: combineValidationSignals) {
(any:AnyObject!) -> RACSignal in
println("ANY: \(any)")
return self.executeLoginRequest()
}
executeSomeActionError = executeLogin!.errors
executeLoginCompleted = executeLogin!.executing
How should I create a RACSignal or RACCommand when the UIView did load? Of course, following the MVVM pattern.
Thanks
You have two options. One more hacky than the other but easier to implement accross your app.
Option 1:
You can write an extension to UIViewController that uses associatedObjects to add a viewDidLoadCommand: RACCommand property to UIViewController. You then swizzle the viewDidLoad() method of UIViewController so that it executes your command on viewDidLoad():
extension UIViewController {
private struct AssociatedKeys {
static var ViewDidLoadCommand: String = "ViewDidLoadCommand"
}
var viewDidLoadCommand: RACCommand? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.ViewDidLoadCommand) as? RACCommand
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.ViewDidLoadCommand,
newValue as RACCommand?,
UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)
)
}
}
}
func swizzled_viewDidLoad() {
self.swizzled_viewDidLoad()
self.viewDidLoadCommand?.execute(nil)
}
}
// In the appDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
method_exchangeImplementations(
class_getInstanceMethod(UIViewController.self, "viewDidLoad"),
class_getInstanceMethod(UIViewController.self, "swizzled_viewDidLoad"))
return true
}
Option 2
You can just subclass UIViewController and implement the viewDidLoadCommandand call it in viewDidLoad()
class ViewControllerSubClass : UIViewController {
var viewDidLoadCommand: RACCommand?
override func viewDidLoad() {
super.viewDidLoad()
self.viewDidLoadCommand?.execute(nil)
}
}
Whichever method you choose all you have to do then is set the command in the your custom viewControllers init method and and it will get executed on viewDidLoad.