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
Related
I am a rookie ios developper . I am confused about how to use a function that I have defined in Application. here my Code
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
}
// I try to use this function in my View's Button
func test() {
print("test")
}
}
I also have use this code in my View
let appDelegate = NSApp.delegate as! AppDelegate
appDelegate.test()
but I have error say
could not cast value of type 'SwiftUI.AppDelegate' (0x7fff8a2c6110) to 'learnSwift.AppDelegate'
thanks all you answer my question
I've tried to link a couple objects in a xib file to my code for the View Controller through IBOutlets, but when I run the code I get the error
'NSUnknownKeyException', reason: '[< UIViewController 0x7f94dfc0f110>
setValue:forUndefinedKey:]: this class is not key value
coding-compliant for the key emailField.'
I've tried deleting all the outlets and reassigning them, and checking that all the connected objects only have one respective outlet each. Also, when unlinking one element, its error goes away, but the same format of the error for a different linked element appears.
import UIKit
import FirebaseAuth
import Firebase
class SignUpViewController: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var usernameField: UITextField!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func toSignUp(_ sender: Any) {
Auth.auth().createUser(withEmail: emailField.text!, password: passField.text!, completion: nil)
Firestore.firestore().collection("users").document(usernameField.text!).setData([
"name" : nameField.text!,
"username" : usernameField.text!,
"email" : emailField.text!
])
TransitionModel().transitionModel(viewControllerName: "LoginViewController", newView: LoginViewController().view!, viewControllerCurrent: self)
}
#IBAction func toLogin(_ sender: Any) {
TransitionModel().transitionModel(viewControllerName: "LoginViewController", newView: LoginViewController().view!, viewControllerCurrent: self)
}
}
import UIKit
import Firebase
class LoginViewController: UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func toLogin(_ sender: Any) {
}
}
import UIKit
import CoreData
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = UIViewController(nibName: "SignUpViewController", bundle: nil)
self.window?.makeKeyAndVisible()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Pono_Beta")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
Thank you in advance for responses.
This happens when you just copy paste view controller.
Goto Storyboard, Select View Controller Open connection inspector and remove connections for emailField and create new Outlet
I am simply trying to make a method in the ViewController class and be able to call it.
Here is my code (I note the 2 ways I tried calling it, and the errors I got):
import UIKit
class ViewController: UIViewController{
func sayHi(name: String){
print("Hi \(name)")
}
}
/*
let viewcontroller = ViewController()
viewcontroller.sayHi(name: "Bob")
*/
//Error: Expressions are not allowed at the top level
/*
ViewController.sayHi(name: "Bob")
*/
//Error: Expressions are not allowed at the top level
//Error: Instance member 'sayHi' cannot be used on type 'ViewController'; did you mean to use a value of this type instead?
So as you can see in the commenting, I tried to call sayHi as a type method and as an instance method. Neither worked. I will ultimately create a function that can take input from a text input, and manipulate it. Is ViewController.swift even the right file to be doing this? If so, how do I call a method that I have defined?
There will be this delegate in appDelegate which will be called when you app is launched. Create your viewController there and add it to the window.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let viewController = ViewController()
window?.rootViewController = viewController
viewController.sayHi()
return true
}
This will work on Playground, but not on Xcode.
Xcode's code is compiled and then you have an app. The first point where a call happens is AppDelegate and from there your first controller and its methods are initialised. Nothing outside a class will be executed.
Use playground for tests or any other online swift playground.
If you want to run sayHi immediately, put it in viewDidLoad and load the app. Delete all further code outside of the class before building again:
override func viewDidLoad() {
super.viewDidLoad()
sayHi()
}
You can create a instance of controller inside a function or a block
when you are working in a class or Xcode projects in Xcode Playground your way of accessing the function sayHi(name: String) in
ViewController works.
For Xcode projects try the following
import UIKit
class ViewController: UIViewController{
func sayHi(name: String){
print("Hi \(name)")
}
}
class SecondViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
let viewcontroller = ViewController()
viewcontroller.sayHi(name: "Bob")
}
}
When you initialise the SecondViewController you can access the ViewController()
To execute the function sayHi(name: String) immediately when the
ViewController() is initialised you can call it in viewDidLoad() or in
func viewWillAppear()
import UIKit
class ViewController: UIViewController{
override func viewDidLoad(_ animated: Bool) {
super.viewDidLoad(animated)
//Call the function hear
sayHi(name: "Bob")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// or call hear
sayHi(name: "Bob")
}
func sayHi(name: String){
print("Hi \(name)")
}
}
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()
}
}
i'm having some problems with my weather app for iOS.
I'm new in programming in xCode, so it could be a silly error.
Anyway, the problem is: I'm trying to add a refresh button in my Single Page App. The button has a IBAction function associated, so that when it is pressed it should get hidden and the activity indicator should appear.
That is the function:
#IBAction func reload() {
refreshButton.hidden = true
refreshActivityIndicator.hidden = false
refreshActivityIndicator.startAnimating()
}
and that is the declaration of the variables:
#IBOutlet weak var refreshButton: UIButton!
#IBOutlet weak var refreshActivityIndicator: UIActivityIndicatorView!
when i run the app and press the refresh button, the app crash and i get this error:
#UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { <--thread 1 signal sigarbt
the console doesn't show anything else.
What could be the problem?
// APPDELEGATE.SWIFT
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
application.setStatusBarHidden(true, withAnimation: .None)
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
//VIEWCONTROLLER.SWIFT
import UIKit
import Foundation
class ViewController: UIViewController {
private let apiKey = "447073dc853014a6fa37376c43d8462b"
#IBOutlet weak var iconView: UIImageView!
#IBOutlet weak var currentTimeLabel: UILabel!
#IBOutlet weak var temperatureLabel: UILabel!
#IBOutlet weak var humidityLabel: UILabel!
#IBOutlet weak var precipitationLabel: UILabel!
#IBOutlet weak var summaryLabel: UILabel!
#IBOutlet weak var refreshButton: UIButton!
#IBOutlet weak var refreshActivityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
refreshActivityIndicator.hidden = true
// base URL
let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
// add coordinates to base url (API syntax)
let forecastURL = NSURL(string: "44.698150,10.656846", relativeToURL: baseURL)
// NSURL SESSION
//The NSURLSession class and related classes provide an API for downloading content via HTTP. This API provides a rich set of delegate methods for supporting authentication and gives your app the ability to perform background downloads when your app is not running or, in iOS, while your app is suspended. With the NSURLSession API, your app creates a series of sessions, each of which coordinates a group of related data transfer tasks. For example, if you are writing a web browser, your app might create one session per tab or window. Within each session, your app adds a series of tasks, each of which represents a request for a specific URL (and for any follow-on URLs if the original URL returned an HTTP redirect).
let sharedSession = NSURLSession.sharedSession()
let downloadTask : NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL!, completionHandler:
{ (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
if (error == nil) {
let dataObject = NSData(contentsOfURL: location) // convert in NSData object
// serialize NSData object in Json as Dictionary
let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as NSDictionary
// instance of Current (Current.swift) init with weatherDictionary
let currentWeather = Current(weatherDictionary: weatherDictionary)
// we put the code in the main queue cause this is relative the UI, that have the first thread (concurrency)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.temperatureLabel.text = "\(currentWeather.temperature)"
self.iconView.image = currentWeather.icon!
self.currentTimeLabel.text = "At \(currentWeather.currentTime!) it is"
self.humidityLabel.text = "\(currentWeather.humidity)"
self.precipitationLabel.text = "\(currentWeather.precipProbability)"
self.summaryLabel.text = "\(currentWeather.summary)"
// Stop refresh animation
self.refreshActivityIndicator.stopAnimating()
self.refreshActivityIndicator.hidden = true
self.refreshButton.hidden = false
})
}
})
downloadTask.resume() // call sharedSession.downloadTaskWithURL -> store json data in location (local temporary memory)
}
#IBAction func reload() {
println("PRESSED")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I haven't got any .h or .m file.
Is reload function even getting called? If you are using storyboard/Xib for creating the UIButton then link the reload function in Xib on touchUpInside Event or if you are creating the UIButton event in code then like below:
Create another UIButton property in .h file:
#property(nonatomic, strong) UIButton *refresh;
In .m file
-(void) viewDidLoad {
self.refresh = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.refresh addTarget:self
action:#selector(reload:) forControlEvents:UIControlEventTouchUpInside];
[self.refresh setTitle:#"Reload" forState:UIControlStateNormal];
self.refresh .frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:self.refresh];
}
-(void) reload:(UIButton*)sender
{
NSLog(#"you clicked on button %#", sender.tag);
if(self.refresh.hidden) {
self.refresh.hidden = false;
} else {
self.refresh.hidden = true;
}
}
Okay it works!
Please don't ask me why :)
I simply deleted the code and rewrote it. And it works. Call it magic.
Thank you all for your answers.