I'm getting started with Xcode, Swift, etc. for iOS development and I was wondering how exactly an instance of my ViewController class is linked to my storyboard. Here's my MRE:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var theButton: UIButton!
#IBAction func buttonPressed(_ sender: UIButton) {
print("The button was pressed")
}
}
I'm guessing that somewhere in the background my app will instantiate ViewController and its various methods such as buttonPressed will be called. However, if I were to hypothetically create two separate instances of my class and the user pressed the button, would both instances get their buttonPressed method called? I'd test this myself but I don't yet know enough about how all of this works.
In the storyboard, check the identity inspector, the ViewController will be linked with storyboard when you set a class name there, check the photo below to understand
Whenever the ViewController is linked with any scene in the storyboard, you can insert action or outlet into that view controller
Related
I am taking reference from tutorial here.
I have one View Controller which contains a Container View. On this Container View I have added Custom Segue i.e. FirstViewController. That means when I opens View Controller it by default shows FirstViewController. And on FirstViewController, I have a Button. And by clicking on this button I want to show SecondViewController but I am not able to get this achieved. I have also added print command on Button click and it prints on console and not switch to another View. Please help.
I have created a delegate in FirstViewController and aa function which reference through ViewController.
Code for FirstViewController.swift
protocol FirstViewDelegate: class {
func sendToSecondViewController()
}
class FirstViewController: UIViewController {
weak var delegate: FirstViewDelegate? = nil
#IBAction func goToSecond(_ sender: UIButton) {
print("test1")
delegate?.sendToSecondViewController()
}
}
Code for ViewController.swift
extension ViewController: FirstViewDelegate{
func sendToSecondViewController() {
container.segueIdentifierReceivedFromParent("second")
}
}
And main.storyboard
Seems you have not set delegate of FirstViewController in ViewController. Something like:
<object of FirstViewController>.delegate = self (Inside ViewController)
Im new to programming and trying to build my own app, I wonder how Im I supposed to link the info I get from the addTask viewcontroller to the tableview cell? At the moment Im just trying to get the text from the textfield and Im going to add the other features later.
What Im trying to do
Refer This :-
Create a global array add remove element from that array on click of your button
You can pass data from one view controller to another using Delegates. Check my ans here. You can set your table view class as delegate of your task view controller. Implement the protocol methods of task view controller get the data and reload table.
Hope it helps.
Happyy Coding!!
You can pass data using Delegation .
In Second ViewController
import UIKit
protocol secondViewDelegate: class {
func passData(arrData : [Any])
}
class SecondViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
weak var delegate: secondViewDelegate? = nil
#IBAction func clickOnButton(_ sender: Any) {
self.delegate.passData([]) // replace your array here
}
}
In FirstViewController
class FirstViewController: UIViewController, UITableViewDataSource, secondViewDelegate
let objectSecondVC: SecondViewController? = storyboard?.instantiateViewController(withIdentifier: "secondVCID") as! SecondViewController?
objectSecondVC?.delegate = self
navigationController?.pushViewController(objectSecondVC?, animated: true)
Second ViewController Delegate Method in FirstViewController
func passData(arrData : [Any]){
// append to your main array
}
It seems like your add task view controller is connected with your table view controller though a segue. So when you moving back from add task view controller, you can use unwind to pass data back. Here is a detailed tutorial with simple instructions and pictures.
In my app I'm building, I've got a Navigation Controller with a View Controller connected as a subview (is that the right word?). I added a UIButton and tried to Control-drag it into my view controller class file, but it's only giving me Outlet and Outlet collection as my options, not Action.
Screenshot of what I'm seeing
It's a pretty simple app, and I've tried removing my Pods as a fix, but so far no luck.
I've also tried manually writing the function and trying to connect it back to the button, but to no avail. Dragging back to the button in the workspace doesn't work, and the function isn't firing when I test the app. Here's the code I tried:
#IBAction func tapSaveButton(_ sender: UIButton) {}
It's probably something simple, so what am I missing here?
EDIT: Also, here's how I'm set up. I have a Navigation Controller with a UINavigationItem that shows a sub ViewController. The button in question is in the sub ViewController and I setup a new swift file to handle that ViewController's class. I'm trying to connect that button into that class file, and that's where it's not working.
Screenshot of my storyboard
Here's my ViewController class's code:
import Foundation
import UIKit
import KeychainSwift
class SettingsViewController : UIViewController {
let keychain = KeychainSwift()
#IBOutlet weak var APIKeyField: UITextField!
#IBOutlet weak var WebSocketIPField: UITextField!
#IBOutlet weak var SettingsSaveButton: UIButton!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
/* My other code, not related */
}
#IBAction func tapSaveButton(_ sender: UIButton) {
// My button actions here.
}
}
Of course it was something dumb. I removed the class from the button, and viola, it let me create an action in my Swift file.
maybe you tried to connect to other viewcontroller
please check again it is correct viewcontroller and connected on storyboard exactly
Right click on the uibutton within storyboard, you should see a list of action options under "Sent Events" the most common one to use is "Touch Up Inside".
Drag from the one you want (circle to the side) onto your view controller and everything should work fine.
EDIT: For clarity, you can even drag from "Touch Up Inside" to the func you've already created so long as it's labeled
#IBAction ...
which your code already has done.
It's also happen with me, when i added localization in my project, from that time which storyboard was added in localization, that storyboard buttons are not showing any action option, only showing outlet options.
I've recently been playing around with swift segues and I'd love to incorporate one in my latest app, the problem is I can't seem to get them to work. So far I've created another view controller SecondViewController and referenced in my ViewController & SecondViewController files as so:
ViewController.swift
import UIKit
class ViewController: UIViewController {
var secondViewController: SecondViewController!
var viewController: ViewController!
override func viewDidLoad() {
//lots more code here
SecondViewController.swift
import UIKit
class SecondViewController: UIViewController {
var secondViewController: SecondViewController!
var viewController: ViewController!
override func viewDidLoad() {
Them in storyboard view I've crtl+dragged a segue from viewController to secondViewController and once that's been created given that segue an identifier using the right hand panel, the segue identifier is GameOver and the segue type is show.
Now I want to call the segue automatically with no interaction from the user, in the final app once the user hits the game over func it would trigger the segue and display a new UIView where the highscore could be displayed with a few other items.
The code I'm using to call the segue is:
self.viewController.performSegueWithIdentifier("GameOver", sender: self)
I receive the following error...
Thread 1:EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0
I also have this error in the output field...
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
I've played around with the names of the segues and the file names and I still get the same error, I'm sure I'm missing something fundamental so hopefully someone can help me work this out.
I've created a new project and uploaded it to GitHub, if anyone could tell me what I'm missing that would be great, here is a link to my GitHub repository https://github.com/rich84ts/TestSingleView
Thank you.
You cannot just throw in some instance properties and expect them to magically do something:
class ViewController: UIViewController {
var secondViewController: SecondViewController!
var viewController: ViewController!
}
Those properties are nil, and sending a message to them will crash your app. You have to give them values.
In your case, the segue emanates from this view controller, so what you actually want to say is
self.performSegueWithIdentifier("GameOver", sender: self)
The other big mistake you are making is that you are saying all this in viewDidLoad. That is way too early! You can't do any segue-ing yet; your view is not even in the interface! Move your code into viewDidAppear: and it will actually work:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.performSegueWithIdentifier("GameOver", sender: self)
}
Your code is still silly and useless, but at least you will see something happen and you can continue developing from there.
What I actually recommend is that you delete your viewDidLoad implementation and put this:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
delay(1) {
self.performSegueWithIdentifier("GameOver", sender: self)
}
}
That will allow the first view controller to appear, wait one second, then summon the second view controller. And so you will learn that everything is hooked up correctly, and can proceed to do something more practical.
You can create a manual segue from the storyboard by control-clicking the ViewController object and dragging from the manual segue to the destination view controller. You can then call this segue with the designated identifier from your source controller. You don't need a reference to the destination view controller to achieve this.
To reference anything from the storyboard in your view controller you need to declare your properties like this:
#IBOutlet var someProperty : UIView?
The #IBOutlet bit makes the property visible on the storyboard and you can control-drag from it to a corresponding object in a view. You can't do this with view controllers though. To access the destination view controller in your source view controller before the segue you need to override func prepareForSegue(_ segue: UIStoryboardSegue,
sender sender: AnyObject?). This allows you to access the destination view controller from the segue-instance before the actual segue (if you need to pass it data for example).
Firstly your self.viewController is a nil object as you only created the variable and didn't initialize it. You can't call a method with nil object. Secondly you have created a push segue from storyboard but you don't have navigation controller in storyboard so self.performSegueWithIdentifier("GameOver", sender: self) will also not work. To use push segue you should have you current viewcontroller in UINavigationController's stack, so first add a UINavigationController in storyboard and make that initial view controller and set ViewController to the rootViewController of the navigation controller then call self.performSegueWithIdentifier("GameOver", sender: self)
Then the code will work. Hope this help.
Quick note before my actual question: I am very new (a few days in) to XCode and Swift. I have programming experience in scientific platforms such as matlab, mathematica, and IGOR.
My question:
In my main view controller I have an IBOutlet for a UIButton which I have implemented in the main story board.
class ViewController: UIViewController {
....
#IBOutlet weak var chip_a1: UIButton!
....
}
Also in my main view controller, and within an IBAction method, I'm able to access the hidden attribute as follows:
#IBAction func chip_a1_touchupinside(sender: UIButton) {
self.chip_a1.hidden = true
}
But when I try to access this property from within a different view controller class as follows:
class endgame: UIViewController {
....
#IBAction func playagain_touchupinside(sender: UIButton) {
var handle = ViewController()
// make the states of all the chips visible
handle.chip_a1.hidden = false // this is the line that gives me an ERROR
dismissViewControllerAnimated(true, completion: nil)
}
....
}
The error is this:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0)
Any help with understanding/fixing this issue would be much appreciated. Happy to provide more detail if I need to.
Best,
Alex.
You create UIViewcontroller with xib File
You have to Change
var handle = ViewController()
to
var handle = ViewController(nibName: "ViewControllerNibfileName", bundle: nil)
as Button is IBOutlet and need the nibfile loaded with viewcontroller