Reputation: 65
Let's say I have a firstViewController and a secondViewController. The first one contains a firstButton and the second one - a secondButton. Here's what I want to do: when user clicks the secondButton, some firstButton's property changes.
Unfortunately, when I create an instance of a firstViewController in a secondViewController and then trying to access a firstButton, I get an error:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
So, technically, I'm trying to do this as follows:
var ins = firstViewController()
@IBAction func secondButtonisPressed(){
ins.firstButton.alpha = 0
}
What is the proper way to implement that?
Thanks in advance.
Upvotes: 5
Views: 6153
Reputation: 6824
Your problem here is that the IBOutlets
of your firstViewController
are only available (!= nil
) after the viewDidLoad()
firstViewController
's method has being called.
In other words, you have to present the view, before you can make any changes to a UIViewController IBOutlet
.
How you can solve this?
Add a variable into FirstViewController
that works as a flag for you.
for example: var hideFirstButton = false
in the viewDidLoad
or viewWillAppear
method of FirstViewController
check for hideFirstButton
's value and hide or show your firstButton
.
Then, before you present your FirstViewController
change the value of hideFirstButton
to the needed for your application to run fine.
UPDATE:
Other workaround, using Storyboard is (This approach has the inconvenient that the completion handler is called after viewWillAppear
() so the button is visible for a second):
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let firstViewController = storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as! FirstViewController
self.presentViewController(firstViewController, animated: true, completion: {
//This lines will be called after the view is loaded so the code will run
firstViewController.firstButton.alpha = 0
})
EXAMPLE: an example at GitHub
Upvotes: 2
Reputation: 31
You could try to do this using delegation, similar to the way Apple does it in their existing frameworks. For an example, look at the way that you use UITableViewDelegate when working with a UITableView object.
If you wanted to use delegation to tell secondViewController
that firstButton
was pressed using delegation, you could do it as follows:
Step 1: Create a protocol containing a method for the button press event.
protocol buttonPressDelegate {
func buttonPressed() -> Void
}
Step 2:
In firstViewController
, declare that you have an instance of an object of type buttonPressProtocol
.
var buttonPressDelegateObj: buttonPressDelegate?
Step 3:
In firstViewController
, initialize your buttonPressDelegateObj
to contain a reference to your instance of secondViewController. If you want you can create a method to set the reference contained in buttonPressDelegateObj
, or do it viewDidLoad
in firstViewController
, etc.
buttonPressDelegateObj = secondViewControllerObj
Step 4:
In secondViewController
, declare that you adopt the buttonPressDelegate
protocol.
class secondViewController: UIViewController, buttonPressDelegate {
Step 5:
In secondViewController
, implement the protocol method buttonPressed()
by adding the function with your desired implementation. Here's an example:
func buttonPressed() {
secondButton.alpha = 0
}
Step 6:
Create an @IBAction on the button in firstViewController
, so that when the button is pressed it calls buttonPressDelegateObj.buttonPressed()
and you can respond to the event
@IBAction func firstButtonPressed() {
if (buttonPressDelegateObj != nil) {
buttonPressDelegateObj.buttonPressed()
}
else {
print("You forgot to set your reference in buttonPressDelegateObj to contain an instance of secondViewController!")
}
}
Note: This is just one way that you could do this. To tell firstViewController
that secondButton
was pressed (go the other way), have firstViewController
implement the protocol buttonPressDelegate
, have secondViewController
contain a reference to firstViewController
as an instance of type buttonPressDelegate?
, and create an @IBAction
in secondViewController
that fires when secondButton
is pressed that calls your the buttonPressDelegate
method.
Note: There is a similar pattern employed in the Android world to get a Fragment
to communicate to an Activity
, that you can read more about here
Upvotes: 2