Function crash in viewController - swift

Hi developers I have this issue with Adobe Audience Manager POD
in my VC I have this
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
ACPAudience.signal(withData: ["ViewedScreen": "ButtonClicked"]) { (response, error) in
if let error = error {
print(error)
} else {
print(response as Any)
}
}
}
every time I run it it crash with this:
dynamic_cast error 2: One or more of the following type_info's has hidden visibility or is defined in more than one translation unit. They should all have public visibility. N20AdobeMarketingMobile6ModuleE, N20AdobeMarketingMobile13ConfigurationE, N20AdobeMarketingMobile22ModuleDetailsInterfaceE.
implementation is correct as far I know
the solution is creating a NSNotification in the app delegate works no crashes or anything weird
code in app delegate is pretty much the same
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
NotificationCenter.default.addObserver(self, selector: #selector(getProfileACP2), name: NSNotification.Name(rawValue: "getProfileACP"), object: nil)
}
#objc private func getProfileACP2(){
ACPAudience.signal(withData: ["ViewedScreen": "ButtonClicked"]) { (response, error) in
if let error = error {
print(error)
} else {
print(response as Any)
}
}
}
then on the VC works like this
override func viewDidLoad() {
super.viewDidLoad()
print("getProfileACP")
print("----------------------------------------------")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "getProfileACP"), object: nil)
print("----------------------------------------------")
print("getProfileACP")
}
after calling it seems like it takes some time after giving the response is not immediately

Related

NotificationCenter Post request never gets received

I am trying to post a message to an observable in my app but for some reason it doesn't work at all and the only thing I can attribute it to is installing https://bugfender.com/ can anyone tell me what is wrong with this code or how to track down the root cause as there is no error messages at all
Both snippets have been moved to AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
NotificationCenter.default.post(name: Notification.Name("TestPost"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(onDidReceiveData(_:)), name: Notification.Name("TestPost"), object: nil)
return true
}
and the receiver functions is
#objc func onDidReceiveData(_ notification:Notification) {
// Do something now
print("XXXXXX received")
}
===== Updating with my actual code for custom capacitor plugin =======
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
... code for receiving notification starts here
NotificationCenter.default.post(name: Notification.Name("TestPost"), object: nil)
... code for receiving notification ends here
return true
}
import Foundation
import Capacitor
#objc(myHelpers)
public class myHelpers: CAPPlugin {
public override func load() {
print("PluginLoaded")
let nc = NotificationCenter.default
nc.addObserver(self, selector: #selector(handleSignal), name: Notification.Name("TestPost"), object: nil)
}
#objc func handleSignal()
{
print("XX WE RECEIVED AN EVENT AT handleSignal")
notifyListeners(
"myPluginEvent",
data: [:],
retainUntilConsumed: true
)
}
}
You need to register your observer before you post the notification.

About the callback of SKStoreReviewController.requestReview()

If the review popup initiated from a view controller shows up, there isn't a way to switch the window focus back to the view controller when the popup is dismissed due to lack of callback function of SKStoreReviewController.requestReview().
I would like to make a call to becomeFirstResponder() when the review popup is dismissed. Any idea?
Is there a way to extend the SKStoreReviewController and add a callback somehow?
Warning this will probably break at some point.
Step 1: add this code to your didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let windowClass: AnyClass = UIWindow.self
let originalSelector: Selector = #selector(setter: UIWindow.windowLevel)
let swizzledSelector: Selector = #selector(UIWindow.setWindowLevel_startMonitor(_:))
let originalMethod = class_getInstanceMethod(windowClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(windowClass, swizzledSelector)
let didAddMethod = class_addMethod(windowClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
if didAddMethod {
class_replaceMethod(windowClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
} else {
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}
return true
}
Step 2: add this class
class MonitorObject: NSObject {
weak var owner: UIWindow?
init(_ owner: UIWindow?) {
super.init()
self.owner = owner
NotificationCenter.default.post(name: UIWindow.didBecomeVisibleNotification, object: self)
}
deinit {
NotificationCenter.default.post(name: UIWindow.didBecomeHiddenNotification, object: self)
}
}
Step 3: Add this UIWindow extension
private var monitorObjectKey = "monitorKey"
private var partialDescForStoreReviewWindow = "SKStore"
extension UIWindow {
// MARK: - Method Swizzling
#objc func setWindowLevel_startMonitor(_ level: Int) {
setWindowLevel_startMonitor(level)
if description.contains(partialDescForStoreReviewWindow) {
let monObj = MonitorObject(self)
objc_setAssociatedObject(self, &monitorObjectKey, monObj, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
Step 4: add this to ViewDidLoad of your controller where you want this
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NotificationCenter.default.addObserver(self, selector: #selector(windowDidBecomeHiddenNotification(_:)), name: UIWindow.didBecomeHiddenNotification, object: nil)
}
Step 5: add the callback for the notification and check that the associated object is a match
#objc func windowDidBecomeHiddenNotification(_ notification: Notification?) {
if notification?.object is MonitorObject {
print("hello")
}
}
Now when a review dialog is closed the notification is triggered and 'print("hello") will be called.
Sometimes iOS app is losing the responder chain, like in the above example of showing StoreKit prompt. What we can do is to detect such events in UIApplication.sendAction and reactivate the first responder chain via becomeFirstResponder. UIKit will reestablish the first responder chain and we can resend the same event.
class MyApplication: UIApplication {
func reactivateResponderChainWhenFirstResponderEventWasNotHandled() {
becomeFirstResponder()
}
override func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool {
let wasHandled = super.sendAction(action, to: target, from: sender, for: event)
if wasHandled == false, target == nil {
reactivateResponderChainWhenFirstResponderEventWasNotHandled()
return super.sendAction(action, to: target, from: sender, for: event)
}
return wasHandled
}
}
This works for me on iOS 13 and does not require any private API access.

firebase, keep user signed in after exiting the app, swift

Sorry if this is a repetative question but I have tried other people's answers here and none of the worked. I was to keep the user signed in after exiting my app. I am using email authentication and backend is Fire base. I tried implementing a function an app delegate but had no luck. any advice is appreciated.
override func viewDidAppear(_ animated: Bool) {
let auth = Auth.auth()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
auth.addStateDidChangeListener { [weak self] (_, user) in
if user != nil {
let vc = self?.storyboard?.instantiateViewController(withIdentifier: "Profile")
self?.present(vc!, animated: true, completion: nil)
} else {
//
}
}
return true
}
}

Userdefault not updating value when app is INACTIVE state or on getting notification when app is TERMINATED

I want to store a value in userdefault to show badge value on tab item. Code working fine when app is in foreground and background state. But its not storing value in userdefault in Inactive state. So, when i launch app i am not able to get received notifications counts after the app termination.
Added following code in AppDelegate class:
public static var badgeValue: String? {
get {
return UserDefaults.standard.string(forKey: "updateBadgeValue")
}
set(newValue) {
UserDefaults.standard.set(newValue, forKey: "updateBadgeValue")
UserDefaults.standard.synchronize()
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if let badgeValue = AppDelegate.badgeValue {
AppDelegate.badgeValue = String(Int(badgeValue)!+1)
} else {
AppDelegate.badgeValue = "1"
}
NotificationCenter.default.post(name: NSNotification.Name("updateBadgeValue"), object: nil)
}
and fetching value by following code in UITabBarController class:
override func viewDidLoad() {
super.viewDidLoad()
updateBadgeValue()
}
func updateBadgeValue() {
if UIApplication.shared.applicationIconBadgeNumber != 0 {
self.tabBar.items![0].badgeValue = String(UIApplication.shared.applicationIconBadgeNumber)
}
NotificationCenter.default.removeObserver(self, name: NSNotification.Name("updateBadgeValue"), object: nil).
NotificationCenter.default.addObserver(self, selector: #selector(updateBadgeValue), name: NSNotification.Name("updateBadgeValue"), object: nil)
}
//Remove observer is removing previous added observer so that previous added observer will call again and again. If i dont remove observer then when i come on UITabBarController class it will add new observer every time.

Checking network status in Swift, observer does not get called

I have imported Reachability.h .m files like written here into my Swift project, but observer / event handler will not get called after start, why?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name: kReachabilityChangedNotification, object: nil)
let hostReachability = Reachability(hostName: "www.apple.com");
hostReachability.startNotifier();
return true
}
func reachabilityChanged(note: NSNotification) { // <- DOES NOT GET CALLED
let reachability: Reachability = note.object as Reachability;
if(reachability.currentReachabilityStatus() != .NotReachable) {
}
}
The Reachability object returned is an autoreleased object , so it has deallocated hence notification is not triggering . You can fix by keeping a strong reference to it.
create a property to hold Reachability object
var reachability:Reachability?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
// Override point for customization after application launch.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name:kReachabilityChangedNotification, object: nil)
reachability = Reachability(hostName: "www.apple.com");
reachability?.startNotifier();
return true
}
This will fix your problem.
The observer's name is changed from ReachabilityChangedNotification to kReachabilityChangedNotification. Notice the "k"
As mentioned in other answers, you need to maintain a strong reference to the Reachability object. If you aren't checking a particular host, then call reachabilityForInternetConnection:
let internetReachability = Reachability.reachabilityForInternetConnection()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name: kReachabilityChangedNotification, object: internetReachability)
internetReachability.startNotifier()
let hasInternet = internetReachability.currentReachabilityStatus().value == 0 ? false : true
// Save to user defaults, log to console, etc.
return true
}
func reachabilityChanged(note: NSNotification) {
var hasInternet = Bool()
if let reachability = note.object as? Reachability {
hasInternet = internetReachability.currentReachabilityStatus().value == 0 ? false : true
}
// Update user defaults, log to console, show error message, etc.
}
For iOS 3+, use below code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NotificationCenter.default.addObserver(self, selector: #selector(checkForReachability(notification:)), name: NSNotification.Name.reachabilityChanged, object: nil)
reachability = Reachability.forInternetConnection()
reachability.startNotifier()
return true
}
// MARK:
// MARK: Check Internet Status
func checkForReachability(notification:NSNotification)
{
let networkReachability = notification.object as! Reachability;
let remoteHostStatus = networkReachability.currentReachabilityStatus()
if (remoteHostStatus == NotReachable)
{
print("Not Reachable")
}
else
{
print("Reachable")
}
}