Unable to call method of ViewController() - ios

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)")
}
}

Related

how to use AppDelegate Function in ViewController in macos application

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

CNContactViewControllerDelegate not called when contact property selected/edited on iOS

The delegate for CNContactviewController is not called when properties get edited or selected.
When editing a new contact, the contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) function is supposed to be called, but it's not.
How do you get notified when the user edits/selects a contact property?
Steps to reproduce:
Copy the view controller below.
Edit/select a contact
property.
Expected behavior:
"yo" is printed every time you edit/select a property.
Actual behavior:
Nothing.
import Foundation
import Contacts
import ContactsUI
class ContactViewController: UIViewController, CNContactViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
createContact()
}
func createContact() {
let contactController = CNContactViewController(forNewContact: nil)
contactController.delegate = self
contactController.allowsEditing = true
contactController.allowsActions = true
contactController.displayedPropertyKeys = [CNContactPostalAddressesKey, CNContactPhoneNumbersKey, CNContactGivenNameKey]
contactController.view.layoutIfNeeded()
present(contactController, animated:true)
}
// =============================================================================================================
// MARK: CNContactViewControllerDelegate Functions
// =============================================================================================================
func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
viewController.dismiss(animated: true, completion: nil)
print("hi")
}
func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool {
print("yo")
return true
}
// =============================================================================================================
// MARK: UIViewController Functions
// =============================================================================================================
override var prefersStatusBarHidden: Bool {
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
There are three initializers for making a CNContactViewController:
Existing contact: init(for:)
New contact: init(forNewContact:)
Unknown contact: init(forUnknownContact:)
The first and third forms call the delegate method contactViewController(_:shouldPerformDefaultActionFor:). The second form does not. That's the one you are using.
With the second flavor, the only event you get is contactViewController(_:didCompleteWith:), and at that point the new contact has already been saved into the database.
When editing a new contact, the contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) function is supposed to be called
No, it isn't. That's just an idea you made up.
Expected behavior: "yo" is printed every time you edit/select a property.
Then stop expecting that.
How do you get notified when the user edits/selects a contact property?
You don't.
When you use a framework like Cocoa, you don't get to make up any expectations you like. Your expectations need to be based on what the framework actually does. You might wish that CNContactViewController and its delegate messages worked as you describe, and that might make a very good enhancement request to Apple. But it is not how it works in fact, so expecting it to do so won't do you any good.

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

Trigger function in VC when modal view is dismissed

I’m trying to trigger a function after dismissing a modal VC (FirstStartVC) back to the main VC. I know that I have to use delegation but it doesn’t work and my debug area stays empty.
In other question topics there were people who had it work exact the same way like below. So I have no idea what I’m doing wrong. Does anyone know what I need to change to the code?
// FirstStartVC.swift
//
import UIKit
import CoreData
import JSSAlertView
protocol NewUser: class {
func newUserAction()
}
class FirstStartVC: UITableViewController, UITextFieldDelegate {
var delegation : NewUser?
func saveNewUser(){
self.delegation?.newUserAction()
self.dismiss(animated: true, completion: nil)
}
}
#IBAction func saveSettings(_ sender: Any) {
self.saveNewUser()
}
override func viewDidLoad() {
super.viewDidLoad()
print (delegation)
}
}
//
// ViewController.swift
//
import UIKit
import UserNotifications
import GoogleMobileAds
import CoreData
import JSSAlertView
class ViewController: UIViewController, UNUserNotificationCenterDelegate, NewUser {
func newUserAction() {
print("Reload some labels")
}
override func viewDidLoad() {
super.viewDidLoad()
var firstStart = FirstStartVC()
firstStart.delegation = self
}
}
Swift 3
In your main VC viewDidLoad add:
NotificationCenter.default.addObserver(self, selector: #selector(mainVc.functionName), name:"NotificationID", object: nil)
and add a function in main VC
func functionName() {
// Do stuff
}
in FirstStartVC call the method with
NotificationCenter.default.postNotificationName("NotificationID", object: nil)
Hope this helps!
A simple edit on Swift 4
NotificationCenter.default.addObserver(self, selector: #selector(self.funcName), name: NSNotification.Name(rawValue: "NotificationID"), object: nil)
Put #objc before the function definition.
#objc func functionName() {
// Do stuff
}
In your code, you have:
func saveNewUser(){
self.delegation?.newUserAction()
self.dismiss(animated: true, completion: nil)
}
}
Simply write the code you want to run after dismissing in completion::
func saveNewUser() {
self.delegation?.newUserAction()
self.dismiss(animated: true, completion: { finished in
// on completion
})
}
}
(You might not even need to say finished in or anything like that.)
If the code you need to execute within newUserAction() is a part of FirstStartVC, you should just call it inside the completion handler of the dismiss(_:animated:) method. However, if you need the code to execute on the VC that presented FirstStartVC, make sure that it conforms to the NewUser protocol. You could do something like this (assuming the presenting VC was named something like PresentingViewController - change it to whatever is the case for your project):
class PresentingViewController: UIViewController {
// However you instantiate the FirstStartVC
let firstStart = FirstStartVC()
// set the delegation property to self
firstStart.delegation = self
}
Then at the bottom of the screen create an extension so it conforms to the protocol:
extension PresentingViewController: NewUser {
func newUserAction() {
// Here you can do whatever you want when the delegation calls this method
}
}
EDIT: - Further recommendation...
I always find it best practice with delegates to use a weak reference to prevent memory problems. To do so you have to make sure to set the protocol as :class, which you've already completed: protocol NewUser: class. So then when you create the property at the top of FirstStartVC you would just say
weak var delegation: NewUser?
Your code will still run the same, I just recommend doing it this way as it's helped me avoid memory issues in numerous instances.

Class protocols not working after updating from Swift 2.3 to Swift 3.0

I have a very basic user class, who os responsible for get user data from Firebase and update the currently screen if needed, everything was working until a decided to update my project to Swift 3.0
This is the User Class
#objc protocol userClassProtocol {
func updateScreen()
#objc optional func sucessUnlockedCategory()
}
class User {
static let sharedInstance = User()
internal var delegate : userClassProtocol?
func fakeClassThatGetsDataFromFirebase() {
//Got data
print("Has new data")
self.delegate?.updateScreen()
}
}
And here is the ViewController:
class FirstViewController: UIViewController, userClassProtocol {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("View will load")
User.sharedInstance.delegate = self
}
func updateScreen() {
print("Screen is going to update")
//Do stuff here
}
}
The logs i get from this are:
Has new Data
View Will Appear
But the function updateScreen() in the view controller never gets called. No errors are being pointed out by Xcode.
Looks like it's just an issue with the timing of your method calls.
Your fakeClassThatGetsDataFromFirebase method is called first, and at that point, your delegate hasn't been set. So self.delegate is nil when calling:
self.delegate?.updateScreen()
This will only work if your viewWillAppear gets called before fakeClassThatGetsDataFromFirebase
It shouldn't get called, according to your code. Nothing calls fakeClassThatGetsDataFromFirebase(), which is what should call updateScreen() on your delegate method.

Resources