Pass data when dismiss modal viewController in swift - ios

I'm trying to pass data from the modal ViewController to his source ViewController. I think I have to use delegation but it doesn't work.
protocol communicationControllerCamera{
func backFromCamera()
}
class Camera: UIViewController{
var delegate: communicationControllerCamera
init(){
self.delegate.backFromCamera()
}
}
class SceneBuilder: UIViewController, communicationControllerCamera{
func backFromCamera(){ // Never called
println("YEAHH")
}
}
The backFromCamera method it's not called. What did I do wrong?

You didn't set a delegate so it was empty when you tried to call backFromCamera().
Here's a simple working example you can test out. Notice the use of the optional type (?) for the delegate.
// Camera class
protocol communicationControllerCamera {
func backFromCamera()
}
class Camera: UIViewController {
var delegate: communicationControllerCamera? = nil
override func viewDidLoad() {
super.viewDidLoad()
self.delegate?.backFromCamera()
}
}
// SceneBuilder class
class SceneBuilder: UIViewController, communicationControllerCamera {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
var myCamera = Camera()
myCamera.delegate = self
self.presentModalViewController(myCamera, animated: true)
}
func backFromCamera() {
println("Back from camera")
}
}
You can find all the information you need in Apple's Swift documentation.

Obviously the chosen answer is correct, but it didn't help me. I did successfully implement protocols though, so I wanted to provide my own explanation in case anyone is struggling with grasping the concept, like I was.
Protocol Code Is Written in Three Places:
Two ViewController Classes
The Protocol itself (code written outside of VC classes)
When I write my protocols, I put them in my "ToolBox" document and I still write comments to remind myself which VCs are doing what. Two examples:
So there is always:
The protocol code (shown above)
Code in a VC which initiates the action
Code in a VC which is delegated to carry out the action
1. The protocol code
See the image above for a reference. Essentially, the protocol code is just where you give the protocol a name and declare what functions you want to remotely call/delegate to. Name the protocol. Declare the names of the functions that can be called upon and declare their parameter types such as string, etc.
2. Code in a VC which initiates the action
This is the code that initiates the protocol. In this example, this is code from a table cell, which needs to delegate some work back to the main table VC. The first screenshot shows the creation of the delegate variable and the second screenshot is the actual use of that variable.
So the below code are table-cell buttons. They all need to trigger code outside of the cell VC, so they all trigger functions using the protocol I declared above.
3. Code in a VC which is delegated to carry out the action
Now the protocol is being called, but which VC answers the call? To answer that question, choose the VC and add the protocol name to the class declaration:
Lastly, you need the actual meat of the whole thing. Not the trigger, not the protocol itself, not the class declaration... but the actual function you want to call:
Hope This Helps
I don't know why protocols just wouldn't sink through my thick skull but they wouldn't. I hope this helps others like me!

Related

iOS Protocol function call on viewDidLoad/setup

I'm trying to create a protocol that I can use on UIViewControllers that will do some setup work when the protocol is attached to a UIViewControler. I currently have the following code.
protocol MyProtocol {
}
extension MyProtocol where Self: UIViewController {
func setup() {
print("We have successfully setup this view controller")
}
}
class MyViewController: UIViewController, MyProtocol {
override func viewDidLoad() {
super.viewDidLoad()
print("Other setup work here") // This line might or might not exist
setup() // Goal is to remove this line, so I don't forget to add it across all my view controllers
}
}
My question is, is there a way to remove the setup() call from within the viewDidLoad function? I think it'd be a lot safer to not have to call that function every time. If there is a view controller that forgets to add that one call, then the setup won't happen, and I want to try to prevent that.
There is a chance that the viewDidLoad function on the view controller that it is attached to will do other work (ex. in this example print("Other setup work here")), or there is a chance it won't do anything except for that setup call.
I'm also not completely opposed to moving that setup function call into a separate function within the view life cycle, but again those other functions in the view life cycle that get called might have other things that need to run as well, so I don't want to completely override them.
I have also considered using the init method somehow, but I think the problem with that is that the view won't have been loaded yet and therefor I can't do the proper setup work like changing a label's text and such.

Swift: hook into lifecycle functions of UIViewController via protocol with default implementation

Is it somehow possible to have a protocol with a default implementation via protocol extension to get some code automatically executed by just implementing the protocol in various places?
Heres an example of what I mean:
protocol Greetable {
func greet()
}
extension Greetable where Self: UIViewController {
func greet() {
print("Hello ViewController")
}
func viewDidLoadMagicFunctionHookIdontKnowIfItIsPossible() {
greet()
}
}
class MyViewController: UIViewController, Greetable {}
So I want to define a protocol, give it default implementations and then hook the extension to let's say viewDidLoad() or other functions without explicitly calling the greet function by myself in every instance.
Subclassing is not possible since I want to use UITableViewController, UIViewController, UINavigationController, UISplitViewController, etc. and I cannot create one generic baseclass for all of them at once.
I also don't want to go through all of my view controllers and call greet() in viewDidLoad() because what if I decide to move the greet() to viewDidAppear? I had to go through all the controllers and move the code.
By the way, the order of when this magic function would be called would not matter at all for me, in case I have two protocols with this magic.
I'm surely not the only one who thought about something like this and there are programmers a thousand times smarter than me who surely can exactly explain why and how or why it is not possible in Swift to "hook" yourself into a certain function call.

Passing Data from SettingsView Controller to Mainstoryboard - Swift

I am a newbie to iOS app development trying to build a tip calculator. The basic functioning of the app is completed. My Mainstoryboard has a segment control which shows three % values such as 10, 20, 30. There is a Settings button which on click takes me to a new page and shows the similar % values in a segment control.
What I want to do is that, when a number is clicked (a segment) it should be saved as the default tip% value. How should I pass this value to the Mainstoryboard function where I have written a function to calculate the tip amount?
I suppose you are using a segue for moving to the other view, so use prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "tipSegue"
{
if let destinationVC = segue.destinationViewController as? OtherViewController {
destinationVC.tipPercent = someValue
}
}
}
You can write a protocol for setting the default percentage, and have your MainViewController conform to that protocol. When a user taps a button in your SettingsViewController you can call a function (defined within the protocol) to let the "delegate" (MainViewController) know what has happened, and set your default variable accordingly. If this is a permanent setting it might be better to use UserDefaults, as this is exactly what that was designed for. Then, upon loading MainViewController you can access that UserDefaults variable, if it exists.
A little protocol help:
Your protocol could be defined very simply - something like this (and this has to be declared outside of your viewControllers - I often do it above the class declaration of a related viewController):
protocol SettingsDelegate {
func didUpdateDefaultTipPercent(to percent: Float)
}
That's it for the protocol declaration, unless you anticipate needing other functions. Note that you don't actually define the functionality of that function - each viewController that conforms to the protocol may have a different definition of that.
Then, in your settingsViewController you might have an optional variable for protocol conformer like this:
weak var settingsDelegate: SettingsDelegate?
and after the user chooses a default percentage you can safely check to see if the delegate exists and pass that new number to the delegate like so:
if let delegate = self.settingsDelegate {
delegate.didUpdateDefaultTipPercent(to: 15.0) //this "15.0" will come from your segmented control action or whatever
}
In your MainViewController, in your prepareFor(segue... you will need to check to see if you are going to settings, and set Main as the delegate:
...
if let settings = segue.destination as? SettingsViewController {
settings.settingsDelegate = self
}
And, finally, you'll need to make your MainViewController conform to the protocol. I usually do this as an extension just to make it easier to find, and to keep it separated from other things:
extension MainViewController: SettingsDelegate {
func didUpdateDefaultTipPercent(to percent: Float) {
self.defaultPercentage = percent
}
}

Passing data from tableview cell to View Controller Swift 2.1

Anyone know why can't I access the variable 'sendTitle' in prepareForSegue from didSelectRowAtIndexPath? I saw some of the tutorials, they are doing the same thing with me, I've no idea why mine got error.
--What I'm doing now is passing value from tableView cell to another view controller.
I'm using Xcode 7 Swift 2.1
you have to declare sendTitle inside your class to make it visible to all methods. Something like follows.
import UIKit
class viewController: UITableViewController {
var sendTitle:String = ""
override func viewDidLoad() {
super.viewDidLoad()
}
//table view delegate methods
// just use sendTitle = cell.lblTitle.text!
}
Because it is declared privately in your didSelectRowAtIndexPath method. It won't be accessible outside of those function. if you want to access it from another function, declare it as global variable in your view controller.

Accessing uibutton action from a different class Swift

I have an UITableView that is loaded from two custom cell xib files.
The second one contains an UIButton.
But since i've added the custom class for xib - it has its own actions and functions, which i cannot access from ViewController.
My goal is to apply some action on UIButton when the custom cell is loaded in the tableview.
My function is defined in ViewController (because all variables are there) and my UIButton action is defined in Custom class for xib.
How do i connect one to another?
Thank you
Here is the solution in swift
If you want to perform action in another class when an event takes place in another class, then you have to use Protocols in your code, so that you can perform the action in another class.
For example
Declare your protocol like this before the class interface
protocol MyDelegateClass {
func btnAction()
}
Define your protocol in the interface of your class like this
var MyDelegateClass! = nil
Now on your button action trigger the protocol like this
#IBAction func btnProtocolAction(sender: AnyObject) {
[delegate btnAction];
}
Now include the protocol in the class like this
class myActionClass: UIViewController, PopUpViewDelegate {
Now assign the protocol to the MyDelegateClass object like this
myProtocolObject.delegate=self
Also define the class which you have declared in MyDelegateClass like
func btnAction() {
print(#"This method will triggered");
}
Hope this helps you.
You can achieve this by simply posting a notification.
NSNotificationCenter.defaultCenter().postNotificationName("buttonClickedNotification", object: nil)
Post this notification from your button method in custom class. You can also pass any data by using object parameter (Here it is nil).
And observe the notification in your viewController.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "buttonClicked:", name: "buttonClickedNotification", object: nil)
And implement buttonClicked() method in your viewController.
func buttonClicked(data: NSNotification)
{
//If any data is passed get it using
let receivedData:NSDictionary = data.object as! NSDictionary //If data is of NSDictionary type.
}
Write a delegate method. This will connect your ViewController and Custom Class. What have you tried already?

Resources