Call external function but no value - swift

good morning,
i have this class:
import Cocoa
class PopOverDetails: NSViewController {
var dID = String()
#IBOutlet weak var txtEmail: NSTextField!
public func fillDetails (ID:NSManagedObjectID) {
print("=== fillDetails ===")
print(ID)
dID = "\(ID)"
}
override func viewDidLoad() {
print("=== viewDidLoad ===")
print(dID)
}
}
i call the function from another view controller
let Controller = PopOverDetails()
Controller.fillDetails(ID: list[0].objectID)
al works fine, but the problem is:
in my function fillDetails, i get the objectID Value which i "send" from the view controller.
but i can't work with this value in the viedidload because it is empty.
this is my output:
=== fillDetails ===
0x40000b <x-coredata://7E006435-3E05-41F9-A3E4-CB8179A319A9/list/p1>
=== viewDidLoad ===
where is my mistake? :)
UPDATE
let vcDetails = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "PopoverDetails") as! NSViewController
popover.contentViewController = vcDetails
popover.show(relativeTo: tblView.rect(ofRow: tblView.selectedRow) , of: tblView, preferredEdge: .maxX)
}

First declare variable in PopOverDetails i.e."id",then
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let secondViewController = storyBoard.instantiateViewController(withIdentifier: "your_identifier") as! PopOverDetails
secondViewController.id = list[0].objectID
self.navigationController?.pushViewController(secondViewController, animated: true)
Now you can get that variable in PopViewController's class

Related

'Could not find a storyboard named 'MainTabController' in bundle NSBundle

the error I'm receiving that I can't seem to fix is
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'Could not find a storyboard
named 'MainTabController' in bundle NSBundle
the app will build and the login screen will display but crashes immediately after with the error stated above.
I have tried all of the following from other post similar to this and have had no luck.
Removing the reference to the storyboard in the info.plist file. When I do this the app does start but I get a black screen as it doesn't load the storyboard.
Fiddle with the Target Membership Main.storyboard.
Remove the storyboard from the project, clean, run and then adding the storyboard back again.
Uninstall Xcode, reinstall Xcode.
Deleting the Derived Data folder.
the problem appears to be with my presentMainScreen() method
func presentMainScreen(){
let mainstoryboard = UIStoryboard(name: "MainTabController", bundle: nil)
let mainTabController = mainstoryboard.instantiateViewController(withIdentifier: "MainTabController") as! MainTabController
mainTabController.selectedViewController = mainTabController.viewControllers?[1]
//let storyboard:UIStoryboard = UIStoryboard(name:"Main", bundle:nil)
//let loggedInVC:LoggedInVC = storyboard.instantiateViewController(withIdentifier: "LoggedInVC") as! LoggedInVC
//self.present(loggedInVC, animated: true, completion: nil)
}
if I comment out the mainTabController lines the app will work perfectly, also if I uncomment the loggedInVC lines and with the mainTabController lines commented out it works perfectly as well.
any suggestions are greatly appreciated.
below is my entire ViewController.swift code and a screenshot of my workspace
workspace
ViewController.swift
import UIKit
import FirebaseAuth
class ViewController: UIViewController {
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
if Auth.auth().currentUser != nil {
print("success")
self.presentMainScreen()
}
}
#IBAction func creatAccountTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text {
Auth.auth().createUser(withEmail: email, password: password, completion:{ user, error in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
}
print("success")
self.presentMainScreen()
})
}
}
#IBAction func loginButtonTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text {
Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
}
print("success")
self.presentMainScreen()
})
}
}
func presentMainScreen(){
let mainstoryboard = UIStoryboard(name: "MainTabController", bundle: nil)
let mainTabController = mainstoryboard.instantiateViewController(withIdentifier: "MainTabController") as! MainTabController
mainTabController.selectedViewController = mainTabController.viewControllers?[1]
//let storyboard:UIStoryboard = UIStoryboard(name:"Main", bundle:nil)
//let loggedInVC:LoggedInVC = storyboard.instantiateViewController(withIdentifier: "LoggedInVC") as! LoggedInVC
//self.present(loggedInVC, animated: true, completion: nil)
}
}
What is the name of your storyboard? Is it MainTabController.storyboard or Main.storyboard?
You are trying to load a storyboard named "MainTabController":
let mainstoryboard = UIStoryboard(name: "MainTabController", bundle: nil)
But previously you called it Main.storyboard:
Fiddle with the Target Membership Main.storyboard.
Also if the main tab controller is in the same storyboard as your login view controller then you can try to use this:
let mainTabController = self.storyboard.instantiateViewController(withIdentifier: "MainTabController")
Your story board is named as Main.storyboard. MainTabController is the controller in the Main storyboard.
let mainstoryboard = UIStoryboard(name: "Main", bundle: nil)
let mainTabController = mainstoryboard.instantiateViewController(withIdentifier: "MainTabController") as! MainTabController
mainTabController.selectedViewController = mainTabController.viewControllers?[1]
let mainstoryboard = UIStoryboard(name: "MainTabController", bundle: nil)
Your storyboard is named "Main"

Add custom view controller as root view controller in my mac application?

I already checked most of the answers to this question but mostly are for Cocoa Touch. I need to implement this in my appdelegate for mac application.
Once user is logged-in he will be redirected to the main screen else go to login screen.
let controller:NSWindowController = NSWindowController()
let viewController:NSViewController
let storyboard = NSStoryboard.init(name: "Main", bundle: nil)
let stringLoginStatus = NSUserDefaults.standardUserDefaults().objectForKey(Constants.Key_LoginStatus) as? String
if stringLoginStatus != nil
{
if stringLoginStatus == "true"
{
viewController = storyboard.instantiateControllerWithIdentifier("Channel") as! NSViewController
}
else{
viewController = storyboard.instantiateControllerWithIdentifier("ViewController") as! NSViewController
}
}
else{
viewController = storyboard.instantiateControllerWithIdentifier("ViewController") as! NSViewController
}
controller.window?.contentViewController = viewController
controller.window?.makeKeyAndOrderFront(self)
It shows and error as controller is not being initialized.
try this code to change your view controller:-
UIApplication.appWindow.rootViewController = UIStoryboard.main.instantiateViewController(withIdentifier: "customViewControl")
//MARK: Make UIApplication extension to get appWindow
extension UIApplication {
class var appWindow: UIWindow! {
return (UIApplication.shared.delegate?.window!)!
}
}
//MARK: Make Storyboard extension to get main screen
extension UIStoryboard {
class var main: UIStoryboard {
let storyboardName: String = Bundle.main.object(forInfoDictionaryKey: "UIMainStoryboardFile") as! String
return UIStoryboard(name: storyboardName, bundle: nil)
}
}

How do I pass data from a View controller into my pop up view controller (swift/ios)

I'm quite new with Swift and I'm making this mini game type app that counts the score and updates the label in the view controller. I want to pass that score from a view controller into another external pop up view controller I created.
#IBAction func Button7Tapped(_ sender: AnyObject)
{
if Index == 13 {
game.score += 1
} else {
let scorepopVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "finalScorePop") as! finalScoreViewController
self.addChildViewController(scorepopVC)
scorepopVC.view.frame = self.view.frame
self.view.addSubview(scorepopVC.view)
scorepopVC.didMove(toParentViewController: self)
}
updateGame()
}
Above is my code for the external pop up view controller I created, which also has a separated .swift file. How would I go about taking my game.score and passing that into my Popup view controller?
In your finalScoreViewController swift file add a new property.
final class FinalScoreViewController: UIViewController {
var score: Int?
}
And then just assign it when you're instantiating it.
#IBAction func Button7Tapped(_ sender: AnyObject) {
if Index == 13 {
game.score += 1
} else {
let scorepopVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "finalScorePop") as! finalScoreViewController
scorepopVC.score = game.score //THIS LINE
self.addChildViewController(scorepopVC)
scorepopVC.view.frame = self.view.frame
self.view.addSubview(scorepopVC.view)
scorepopVC.didMove(toParentViewController: self)
}
updateGame()
}
It is better to use storyboard to open the ViewController. In storyboard, right click and drag from you button to the second view controller (the one that you wish to open).
Choose the segue type that you wish to use. In your case, I think Present Modally will work fine.
You will see a line between the two UIViewControllers in storyboard. That is the segue. Tap on it. In the Attributes inspector give the segue an identifier. For instance "myFirstSegue".
Then in the code of the UIViewController that contains your button override prepare(for:sender:). This method is called when preparing for the segue to happen. I.o.w when you tap on the button. You have access to the destination UIViewController and can therefor access and set the properties on it.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "myFirstSegue" {
if let vc = segue.destination as? MyViewController {
//here you set your data on the destination view controller
vc.myString = "Hello World"
}
}
}
Note that we check the identifier, because all segues that go from this ViewController to other ViewControllers will call prepare(for:sender:)
It's quite simple, Just add a property in your finalScoreViewController (if you are not already done this) and -for example- call it score:
class finalScoreViewController: UIViewController {
var score: String?
// ...
Add this line to the Button7Tapped action (where you set a value for finalScoreViewController's score):
let scorepopVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "finalScorePop") as! finalScoreViewController
// add this line:
scorepopVC.score = "My score"
self.addChildViewController(scorepopVC)
scorepopVC.view.frame = self.view.frame
self.view.addSubview(scorepopVC.view)
scorepopVC.didMove(toParentViewController: self)
Finally, in finalScoreViewController:
override func viewDidLoad() {
super.viewDidLoad()
if let scr = score {
print(scr)
}
}
Hope that helped.
You do not actually have to pass the variable to the next view controller. All you have to do is create a variable outside of the View Controller class, and voila, you can access your variable from anywhere, in any swift file. For example:
var score = 0
class ViewController: UIViewController {
override func viewDidLoad(){
super.viewDidLoad()
}
#IBAction func Button7Tapped(_ sender: AnyObject){
score += 1
}
}
And then in the other View Controller, you would have something like this:
#IBOutlet weak var scoreLabel: UILabel!
class ViewController: UIViewController {
override func viewDidLoad(){
super.viewDidLoad()
var timer1 = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateScore), userInfo: nil, repeats: true)
}
#objc func updateScore() {
scoreLabel.text = "You have \(score) points!"
}

Having issues setting delegate with Observer Pattern

I'm trying to realize the Observer Pattern and I'm experiencing some difficulty as my delegate doesn't seem to be setting properly.
In my Main.storyboard I have a ViewController with a container view. I also have an input box where I'm capturing numbers from a number keypad.
Here's my storyboard:
I'm trying to implement my own Observer Pattern using a protocol that looks like this:
protocol PropertyObserverDelegate {
func willChangePropertyValue(newPropertyValue:Int)
func didChangePropertyValue(oldPropertyValue:Int)
}
My main ViewController.swift
class ViewController: UIViewController {
#IBOutlet weak var numberField: UITextField!
// observer placeholder to be initialized in implementing controller
var observer : PropertyObserverDelegate?
var enteredNumber: Int = 0 {
willSet(newValue) {
print("//Two: willSet \(observer)") // nil !
observer?.willChangePropertyValue(5) // hard coded value for testing
}
didSet {
print("//Three: didSet")
observer?.didChangePropertyValue(5) // hard coded value for testing
}
}
#IBAction func numbersEntered(sender: UITextField) {
guard let inputString = numberField.text else {
return
}
guard let number : Int = Int(inputString) else {
return
}
print("//One: \(number)")
self.enteredNumber = number // fires my property observer
}
}
My ObservingViewController:
class ObservingViewController: UIViewController, PropertyObserverDelegate {
// never fires!
func willChangePropertyValue(newPropertyValue: Int) {
print("//four")
print(newPropertyValue)
}
// never fires!
func didChangePropertyValue(oldPropertyValue: Int) {
print("//five")
print(oldPropertyValue)
}
override func viewDidLoad() {
super.viewDidLoad()
print("view loads")
// attempting to set my delegate
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let pvc = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
print("//six \(pvc)")
pvc.observer = self
}
}
Here's what my console prints:
What's happening
As you can see when my willSet fires, my observer is nil which indicates that I have failed to set my delegate in my ObservingViewController. I thought I set my delegate using these lines:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let pvc = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
print("//six \(pvc)")
pvc.observer = self
However, I must be setting my delegate incorrectly if it's coming back nil.
Question
How do I properly set my delegate?
You are calling into the storyboard to instantiate a view controller and setting it as the observer, however that instantiates a new instance of that view controller, it doesn't mean that it is referencing the one single "view controller" that is in the storyboard. ObservingViewController needs another way to reference the ViewController that has already been created.
So #Chris did reenforce my suspicions which helped me to figure out a solution for assigning my delegate to my view controller properly.
In my ObservingViewController I just need to replace the code in my viewDidLoad with the following:
override func viewDidLoad() {
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let vc = app.window?.rootViewController as! ViewController
vc.observer = self
}
Rather than creating a new instance of my view controller, I'm now getting my actual view controller.

Sending array data from one view controller to another

I am trying to copy an array from one view controller to another view controller, but somehow it does not work.. I have tried using this code:
let otherVC = TerningspilletViewController()
mineSpillere = otherVC.mineSpillere2
println("otherVC")
In the view controller i want to send the data from has this code:
var mineSpillere = ["Spiller 1", "Spiller 2", "Spiller 3"]
The view controller that is going to received this data, has this code:
var mineSpillere2 = [String]()
the "var mineSpillere" is going to show the text, but when i try to show it, it says that the "var mineSpillere" is empty. Any suggestions/ideas?
If you want to access array of another viewController then you can save it in memory and for that you can use NSUserDefaults this way:
//save
var mineSpillere = ["Spiller 1", "Spiller 2", "Spiller 3"]
var defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(mineSpillere, forKey: "YourKey")
Now you can read it from anywhere this way:
//read
if let testArray : AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("YourKey") {
var readArray : [NSString] = testArray! as! [NSString]
println(readArray)
}
And if you want to do with your old way here is code:
FirstViewController.swift
import UIKit
class FirstViewController: UIViewController {
var mineSpillere = ["Spiller 1", "Spiller 2", "Spiller 3"]
override func viewDidLoad() {
super.viewDidLoad()
}
}
SecondViewController.swift
import UIKit
class SecondViewController: UIViewController {
var mineSpillere2 = [String]()
override func viewDidLoad() {
super.viewDidLoad()
let otherVC = FirstViewController()
mineSpillere2 = otherVC.mineSpillere
println(mineSpillere2) //[Spiller 1, Spiller 2, Spiller 3]
}
}
first checkout are you using story board
if you are using storyboard
let otherVc = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("storyboardIdendifier") as? TerningspilletViewController
otherVC.mineSpillere2 = mineSpillere
println(otherVc)
otherwise do like this
let otherVC = TerningspilletViewController()
otherVC.mineSpillere2 = mineSpillere
println("otherVC")
if you are using storyboards, I suggest passing the data in prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "TerningspilletViewSegue" {
let otherVc = segue.destinationViewController as! TerningspilletViewController
otherVc.mineSpillere = mineSpillere
}
}
Try this code working fine sending data from one viewController to another viewcontroller.just reference of storyboard id you can send data from one view to another view .Then we create that class object based on that object reference we can access that array and those class properties then just append it.
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let secondView = storyBoard.instantiateViewController(withIdentifier: "tableView") as! TableViewController.
self.present(secondView, animated: true) {
let data = nameArray
secondView.models.append(data!)
secondView.tableView.reloadData()
}