Firebase Crashes iMessage Extension - ios

Inside of my MessagesViewController (first view controller to load) I have the code:
override func viewDidLoad() {
super.viewDidLoad()
FirebaseApp.configure()
ref = Database.database().reference()
}
It works to load firebase into my iMessage extension initially, but then it crashed the extension when it tries to run again once the app exits and you are viewing the transcript. I used breakpoints to pinpoint the error, and it is FirebaseApp.configure() running for the second time. Does anyone know how to prevent this crash?

I got it to work through:
override func viewDidLoad() {
super.viewDidLoad()
if(FirebaseApp.app() == nil){
FirebaseApp.configure()
ref = Database.database().reference()
}
}

Related

Frustrating memory leak when loading an interstitial ad in Swift

I am dealing with an infuriating memory leak in regards to loading an interstitial ad via AdMob. When observing the memory in Xcode & Instruments, the memory jumps 10 MB every time I visit the view controller hosting the ad. Also when closing the app on my phone and reopening it, causes the memory to jump 30-40 mb as well which is just ridiculous.
I have tried profiling this in Instruments and the memory being allocated are all system libraries and nothing that points out to what is wrong. I have read other Stack Overflow answers such as ADMOB Memory Leaking?
but no answer has helped me so far. Maybe somebody can tell me what is wrong with my code? I have followed the exact documentation AdMob provides which is https://developers.google.com/admob/ios/interstitial and all works fine except this crazy memory leak. Here is the exact code that is causing the leak below.
class ViewController: UIViewController, GADInterstitialDelegate {
var interstitial: GADInterstitial!
override func viewDidLoad() {
interstitial = createAndLoadInterstitial()
interstitial.delegate = self
}
func update() {
if interstitial.isReady {
interstitial.present(fromRootViewController: self)
}
}
func createAndLoadInterstitial() -> GADInterstitial {
let interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
interstitial.delegate = self
let request = GADRequest()
interstitial.load(request)
return interstitial
}
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
interstitial = createAndLoadInterstitial()
}
// I am calling update() inside a button when pressed in this VC.
I just want to say that this actually has been solved by me. I did as one of the above stated in the comments. I took my code that was on the view controller hosting the interstitial ad and moved it to the app delegate. I simply then just referenced the interstitial ad object whenever I need it in my project. This brought the memory back down to whatever it allocated upon visiting the controller hosting the ad. For those that want to see a very simple example of what this looks like in the app delegate:
import UIKit
import GoogleMobileAds
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GADInterstitialDelegate {
var myInterstitial: GADInterstitial!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GADMobileAds.sharedInstance().start(completionHandler: nil)
myInterstitial = createAndLoadInterstitial()
return true
}
func createAndLoadInterstitial() -> GADInterstitial {
let interstitial = GADInterstitial(adUnitID: "yourAdID")
interstitial.delegate = self
let request = GADRequest()
interstitial.load(request)
return interstitial
}
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
myInterstitial = createAndLoadInterstitial()
}
I also had this issue and turns out I just needed a pod update.
In version 7.53.0 the update included 'Fixed the GADBlockSignalSource memory leak that occurred when loading ads' which may relate to the interstitial memory leak issue we were experiencing.
Release notes:
https://developers.google.com/admob/ios/rel-notes

Initial navigation view controller of AuthUI not working under Xcode 10.2

I recently upgraded to Xcode 10.2.
Before the upgrade I could use the stock Initial Navigation View Controller of AuthUI from Firebase Realtime Database, I could sign up and login to Firebase without problems, now I get a "welcome" screen only.
I'm using the same code as before. (note that the authentification works in my old project even with Xcode 10.2, I cannot make any new projects using the Initial Navigation View Controller of AuthUI)
I tried the same code that worked with Xcode 10 and Swift 4.2
I even set up another test project from zero to diagnose the problem, I reached out to the Firebase team about this, I'm posting my question here in the meantime, hoping for a fast answer.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func loginTapped(_ sender: Any) {
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else { return }
authUI?.delegate = self
let authViewController = (authUI?.authViewController())!
present(authViewController, animated: true, completion: nil)
}
}
extension ViewController: FUIAuthDelegate {
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
guard error == nil else { return }
performSegue(withIdentifier: "goHome", sender: self)
}
}
The problem is that the authentification page won't load up, I cannot sign up/login; therefore the performSegue never fires.
Add this to your code :
authUI?.providers = [FUIEmailAuth()]
Plus, you have modify the pod file and add: pod 'FirebaseUI/Email' if you are using email.

Aren't KeychainWrapper items deleted from iPhone after we remove the application? (Swift 4.2)

I have created one single application to explain my question well.
There is a button in the page(ViewController)
Here is the ViewController.swift file
import UIKit
import SwiftKeychainWrapper
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let resultOfTheMethod = checkKeychainWrapperExistOrNot()
print("checkKeychainWrapperExistOrNot method result: \(resultOfTheMethod)")
}
#IBAction func btnPressed(_ sender: UIButton) {
saveSomeDummyDataInToTheKeychainWrapper()
}
func saveSomeDummyDataInToTheKeychainWrapper()
{
KeychainWrapper.standard.set("TEST_123", forKey: "someKey4KeychainWrapper")
}
func checkKeychainWrapperExistOrNot () -> Bool {
if let _ = KeychainWrapper.standard.string(forKey: "someKey4KeychainWrapper")
{
return true
}
return false
}
}
Let me explain what i did in order:
I have plugged my iPhone in to my mac. And then I run the app as a first time with using my iPhone. I got this output from viewDidLoad method:
checkKeychainWrapperExistOrNot method result: false
And then I have clicked the button. After that I have closed the application and opened it again. I got this output:
checkKeychainWrapperExistOrNot method result: true
And then i have done with these steps in order:
Removed the app from my iPhone,
Clicked: Product > "Clean Build Folder",
And then re run the application. I got this output:
checkKeychainWrapperExistOrNot method result: true
Result is: KeyChainWrapper item is not deleted. I would like to confirm it because it is weird little bit: I am done with this application: I have removed it from my phone. But some files still exist in my iPhone related with this removed app.
So my first question is: Aren't KeyChainWrapper items deleted when we remove the application from iPhone? When are these deleted?
Second question: How can I remove all KeychainWrapper items? Let's assume I have lots of KeychainWrapper items like this:
KeychainWrapper.standard.set("TEST_123", forKey: "someKey4KeychainWrapper")
KeychainWrapper.standard.set("TEST_123", forKey: "someKey4KeychainWrapper2")
KeychainWrapper.standard.set("TEST_123", forKey: "someKey4KeychainWrapper3")
How can I remove all of them?

IBAction causes EXC_BAD_ACCESS in AppDelegate

I am writing a project for iOS in swift using the DJI Mobile SDK and the UXSDK sample application (found here: https://github.com/dji-sdk/Mobile-UXSDK-iOS).
I added a ViewController with an IBAction getData(_ sender:) which sends a message successfully to a DJI product. When the IBAction completes, the app crashes with a EXC_BAD_ACCESS error in AppDelegate.swift
Error flag in AppDelegate
import UIKit
import Foundation
//To use DJI Bridge app, change `useBridge` to true and add bridge app
IP address in `debugID`
let useBridge = false
let debugIP = "BRIDGE_APP_IP_ADDRESS_HERE"
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,
UISplitViewControllerDelegate {
var window: UIWindow?
open var productCommunicationManager = ProductCommunicationManager()
open var communicationsViewController = CommunicationsViewController()
open var osdkDevice:OnboardSDKDevice?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Start the registration at the launch of the app. This can be retriggered at anytime from the main view.
// DJI App key needs to be registered in the Info.plist before calling this method.
self.productCommunicationManager.registerWithProduct()
return true
}
}
Here is the view controller. It isn't the main one, but it is navigated to through the main view controller.
import UIKit
import Foundation
import DJISDK
import DJIUXSDK
class CommunicationsViewController: UIViewController, UITextViewDelegate {
//This is instantiated as a UIViewController as soon as app launches
//The reference in appDelegate is reassigned every time the view launches
//MARK: Properties
#IBOutlet weak var DataDisplay: UITextView!
open weak var appDelegate = UIApplication.shared.delegate as? AppDelegate
//MARK: Methods
override func viewDidLoad() {
super.viewDidLoad()
appDelegate?.communicationsViewController = self
appDelegate?.productCommunicationManager.connectToProduct()
appDelegate?.productCommunicationManager.connectedProduct = DJISDKManager.product()
if (appDelegate?.productCommunicationManager.connectedProduct?.model != nil){
self.DataDisplay.text = (appDelegate?.productCommunicationManager.connectedProduct.model)
}
appDelegate?.osdkDevice = OnboardSDKDevice()
appDelegate?.osdkDevice?.delegate = appDelegate?.osdkDevice
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: Actions
#IBAction func back(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
#IBAction func getData(_ sender: UIButton) {
//Create 4 bytes of 0's
let data = Data(count: 4)
appDelegate?.osdkDevice?.sendDataFromMobile(toOnboard: data, withCompletion: nil)
//App crashes after exiting scope
}
}
I have found that EXC_BAD_ACCESS is caused by trying to access memory that is no longer available. I have double checked the connections of all my IBActions and IBOutlets and they seem to be okay.
This is the error message from "bt" in the console
Console and assembly from exception breakpoint
Could somebody help me diagnose the crash?
iOS programming and Swift are both pretty new to me, so if there anything missing in this description please let me know. Thanks

Perform Segue in ViewDidLoad [duplicate]

This question already has answers here:
Perform Segue on ViewDidLoad
(12 answers)
Closed 4 years ago.
I`m trying to perform a segue if its the first time the app is loading.
I can see my print message in the debugger, but the Perform Segue is not working. I don't get any errors.
Can somebody please tell me whats wrong?
import UIKit
import LocalAuthentication
let isFirstLaunch = UserDefaults.isFirstLaunch()
extension UserDefaults {
// check for is first launch - only true on first invocation after app install, false on all further invocations
// Note: Store this value in AppDelegate if you have multiple places where you are checking for this flag
static func isFirstLaunch() -> Bool {
let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag"
let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag)
if (isFirstLaunch) {
UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag)
UserDefaults.standard.synchronize()
}
return isFirstLaunch
}
}
class loginVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if isFirstLaunch == false {
performSegue(withIdentifier: "setPassword", sender: self)
print("testFalse") }
else {
performSegue(withIdentifier: "setPassword", sender: self)
print("testTrue")}
// Do any additional setup after loading the view, typically from a nib.
}
You can't use performSegue() from within viewDidLoad(). Move it to viewDidAppear().
At viewDidLoad() time, the current view isn't even attached to the window yet, so it's not possible to segue yet.
You can also use a different approach - change the main window's rootViewController to the view controller of your choice depending on isFirstLaunchboolean
UIApplication.shared.keyWindow?.rootViewController = setPasswordViewController

Resources