Hi guys i would want to fire a method in SecondViewController from FirstViewController when the condition is meet. So i have used delegate to do so and my code is as follow:
FirstViewController:
import UIKit
import CoreBluetooth
import Foundation
class BluetoothViewController: UIViewController, ValueChangedDelegate {
if (characteristic.UUID == CBUUID(string: "2AF0")){
DataReceived.Single_Axis = Double(CharValue)
func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
let singleaxisview = SingeAxisViewController()
singleaxisview.delegate = self
singleaxisview.valueChangedNotifyEveryone()
println("btfired")
}
SecondViewController
import UIKit
import CoreGraphics
protocol ValueChangedDelegate
{
func valueChanged(nValue : String)
}
class SingeAxisViewController: UIViewController {
var delegate : ValueChangedDelegate?
func valueChangedNotifyEveryone()
{
println("hello")
delegate?.valueChanged("changed value")
}
Can somebody point out to me what i missed?
Instead of BTController!.delegate = self you will have to use object of FirstViewController and set the delegate and you will also need to initialise the FirstViewController object. here is a sample code if you want to implement it. the first view controller implements the delegate methods and on call of btnClicked the second view controller is called and you get the response back to first view controller in the valueChanged method
import UIKit
class FirstViewController: UIViewController, ValueChangedDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
lbl.text = "inital value"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
#IBOutlet weak var lbl: UILabel!
#IBAction func btnClicked(sender: AnyObject)
{
let secondViewController = SecondViewController()
secondViewController.delegate = self
secondViewController.valueChangedNotifyEveryone()
}
func valueChanged(nValue : String)
{
print(nValue)
lbl.text = nValue
}
}
Second view controller which implements the protocol and the also calls the protocol method from valueChangedNotifyEveryone method
import UIKit
protocol ValueChangedDelegate
{
func valueChanged(nValue : String)
}
class SecondViewController: UIViewController {
var delegate : ValueChangedDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func valueChangedNotifyEveryone()
{
delegate?.valueChanged("changed value")
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
Related
I am trying to pass data between my two view controllers in my UIscrollview. I am trying to use delegation to send data between Viewcontroller1 and Viewcontroller2. The delegate is Viewcontroller, while the delegator is Viewcontroller1 and Viewcontroller2.
In the code posted below, when the switch in Viewcontroller1 is toggled, it makes the switch in Viewcontroller2 put to the "off" state. I keep on getting the
fatal error: unexpectedly found nil while unwrapping an Optional value
error when I run it, but I have no clue what is causing this problem. Any ideas why?
Below is the Viewcontroller that contains the Uiscrollview and the subviews/childviews
import UIKit
class ViewController: UIViewController, testing {
var vc1 = ViewController1(nibName: "ViewController1", bundle: nil)
var vc2 = ViewController2(nibName: "ViewController2", bundle: nil)
#IBOutlet weak var scrollView: UIScrollView!
func test1() {
vc2.switch2.on = false
}
override func viewDidLoad() {
super.viewDidLoad()
self.addChildViewController(vc1)
self.scrollView.addSubview(vc1.view)
vc1.didMoveToParentViewController(self)
var frame1 = vc2.view.frame
frame1.origin.x = self.view.frame.size.width
vc2.view.frame = frame1
self.addChildViewController(vc2)
self.scrollView.addSubview(vc2.view)
vc2.didMoveToParentViewController(self)
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width * 2, self.view.frame.size.height);
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
here is the Viewcontoller1 code
protocol testing{
func test1()
}
class ViewController1: UIViewController {
var delegate:testing?
#IBOutlet weak var switch1: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
let vc = ViewController()
self.delegate = vc
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func switch1toggled(sender: AnyObject) {
delegate?.test1()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
and here is the Viewcontroller 2 code
import UIKit
class ViewController2: UIViewController {
#IBOutlet weak var switch2: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func switch2toggled(sender: AnyObject) {
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
sorry for the long post, I have been stuck for a week on how to change the state of another switch from toggling a switch in another class, and this was the most efficient way that I found
Try This:
ViewController1
class ViewController1: UIViewController {
let defaults = NSUserDefaults.standardUserDefaults()
let switch1Key = "view1Switch"
override func viewWillAppear(animated: Bool) {
view1Switch.on = defaults.boolForKey(switch1Key)
}
#IBOutlet weak var view1Switch: UISwitch!
#IBAction func view1SwitchChanged(sender: UISwitch) {
defaults.setBool(view1Switch.on, forKey: switch1Key)
}
}
ViewController2
class ViewController2: UIViewController {
let defaults = NSUserDefaults.standardUserDefaults()
let switch1Key = "view1Switch"
override func viewWillAppear(animated: Bool) {
view2Switch.on = defaults.boolForKey(switch1Key)
}
#IBOutlet weak var view2Switch: UISwitch!
#IBAction func view2SwitchChanged(sender: UISwitch) {
defaults.setBool(view2Switch.on, forKey: switch1Key)
}
}
This method syncs the state of the two UISwitches using viewWillAppear and NSUserdefaults. The basic thought pattern is that you save the state of the switch to NSUserdefaults so that when either ViewController1 or ViewController2 is instantiated the view1Switch or view2Switch outlet's .on property is set to the saved value.
Caveats:
The first value for the switch when ViewController1 is instantiated (in the first app run) will be off because boolForKey returns false when there is no saved value. This can be hacked by using view1Switch.on = true directly after view1Switch.on = defaults.boolForKey(switch1Key)
This method makes the switches have the same value. In order to make them have different values, you can use a ! operator like so in ViewController2 view2Switch.on = !defaults.boolForKey(switch1Key). This way switch 1 will always be the opposite of switch 2.
I recommend this method over delegation because, while delegation is powerful, its power doesn't seem needed here.
If you have any questions please ask! :D
I have the following 2 controllers listed below. I'm using delegation to try and create a progressWindow which will run code and print it nicely but where the code is arbitrary.
The closures are defined by the class conforming to the protocol (in my case SyncViewController), but I want to change the UI of the progressWindowViewController from SyncViewControllers codeToRun {} closure. How do I do this?
SyncViewController.swift
import UIKit
class SyncViewController: UIViewController, progressWindowDelegate {
var codeToRun = {
//(self as! ProgressWindowViewController).theTextView.text = "changed the text"
print("code to run")
}
var codeToCancel = {print("code to cancel")}
var titleToGive = "Starting Sync..."
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func yesSyncButtonAction(sender: UIButton) {
//Segue to the ProgressWindowViewController...
}
#IBAction func noSyncActionButton(sender: UIButton) {
tabBarController?.selectedIndex = 1 //assume back to inventory section
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "SyncToProgressSegue"){
let progressWindow = segue.destinationViewController as! ProgressWindowViewController
progressWindow.controllerDelegate = self //sets the delegate so we have reference to this window still.
}
}
}
ProgressWindowViewController.swift
import UIKit
protocol progressWindowDelegate{
var titleToGive : String {get}
var codeToRun : ()->() {get}
var codeToCancel : ()->() {get}
}
class ProgressWindowViewController: UIViewController {
#IBOutlet weak var theTextView: UITextView!
#IBOutlet weak var theProgressBar: UIProgressView!
#IBOutlet weak var navItemLabel: UINavigationItem!
//Sets delegate
var controllerDelegate:progressWindowDelegate!
override func viewDidLoad() {
super.viewDidLoad()
navItemLabel.title! = controllerDelegate.titleToGive
dispatch_async(dispatch_get_main_queue(),{
self.controllerDelegate.codeToRun() //Will run code accordingly.
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func cancelNavItemButtonAction(sender: UIBarButtonItem) {
dispatch_async(dispatch_get_main_queue(),{
self.controllerDelegate.codeToCancel()
})
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
An example of how his might be used is downloading thousands of inventory records with images, which would print the inventory details as it grabs them into the progressWindow.
But this progressWindow could also be used for other large/small tasks that need to print particular stuff into the progressWindow textarea (like logging in and therefore coming from a different view controller than sync in my example). The idea is to make it a dynamic class.
Instead of creating a variable, just use a function/method?
override func viewDidLoad() {
super.viewDidLoad()
dispatch_async(dispatch_get_main_queue(),{
self.controllerDelegate?.codeToRun(self)
})
}
.
protocol progressWindowDelegate : class {
var titleToGive : String {get}
func codeToRun(progressWindowViewController:ProgressWindowViewController)
var codeToCancel : ()->() {get}
}
class SyncViewController: UIViewController, progressWindowDelegate {
func codeToRun(progressWindowViewController:ProgressWindowViewController) {
print("code to run")
}
Also make delegate weak and optional:
delegate weak var controllerDelegate:progressWindowDelegate? = nil
I have the following structure
Main ViewController: it is responsible to call the (A) view controller.
(A) ViewController: create an CustomClass instance and has a delegate for this class.
CustomClass: in each period of 1 second, a message is sent to (A) view controller via delegate.
Until here all works fine. Once I returned to Main ViewController the delegate keep alive, in other words, the delegate updates A(ViewController) variable. I checked that viewDidDisappear of (A) ViewController is called.
When I return again from Main ViewController to (A) ViewController, a new variable instance is created. I don't understand this anyway.
Besides this doubt, I would like to understand why the delegate keep alive when I return to main view controller. I am using a UINavigationItem to navigation.
I am a beginner in IOS development.
Thanks advanced!!!
Edit 1:
The (A)ViewController is called from MainViewController by Segue. The segue was added via storyboard.
MainViewController.swift
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
AViewController.swift
class ScanDevices : UIViewController, CustomClassDelegate {
var myInts : [Int] = []
var customClass : CustomClass!
override func viewDidLoad() {
super.viewDidLoad()
print("viewDidLoad")
if customClass == nil {
customClass = CustomClass()
customClass.customClassDelegate = self
}
}
override func viewWillAppear(animated: Bool) {
print("viewWillAppear")
}
override func viewDidAppear(animated: Bool) {
print("viewDidAppear")
}
override func viewWillDisappear(animated: Bool) {
print("viewWillDisappear")
}
override func viewDidDisappear(animated: Bool) {
print("viewDidDisappear")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func didDiscoverPeripheralInt(peripheral: Int) {
myInts.append(peripheral)
print("Number = \(myInts.count)")
}
}
CustomClass.swift
class CustomClass : NSObject {
var customClassDelegate : CustomClassDelegate?
// MARK: init
override init() {
super.init()
NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "writeInt", userInfo: nil, repeats: true)
}
func writeInt () {
CustomClassDelegate?.didDiscoverPeripheralInt(3)
}
}
var customClassDelegate : CustomClassDelegate?
You are holding a string reference to your delegate.
It needs to be
weak var customClassDelegate : CustomClassDelegate?
Take a look at the following document :
http://krakendev.io/blog/weak-and-unowned-references-in-swift
Your CustomClass holds strong reference to the delegate. You have to mark the property with weak:
weak var customClassDelegate : CustomClassDelegate?
I am a little confused on how to use container views correctly, i will try to explain it the best i can.
I have a main view controller that has an animation function.
import UIKit
class MainViewController: UIViewController,UIPickerViewDataSource,UIPickerViewDelegate {
// Run view setups
override func viewDidLoad() {
super.viewDidLoad()
}
func closePicker(){
self.view.layoutIfNeeded();
UIView.animateWithDuration(0.5, animations: {
self.countryPickerConst.constant = -206;
self.view.layoutIfNeeded();
})
}
}
In interface builder i have added a container view with a new view controller that contains a button like so:
import UIKit
class ContainerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func runAnimation(sender: UIButton) {
//I want to call the function in my other view controller
}
}
In the action runAnimation i want to call the function in the MainViewController. If i just create an instance of MainViewController and call the function it seems to loose its 'self' relevance.
If someone could explain to me the best practice for doing things like this that would be great.
Thanks
From your explanation MainViewController is the parent of ContainerViewController so to access closePicker from ContainerViewController you would do:
#IBAction func runAnimation(sender: UIButton) {
(self.parentViewController as! MainViewController).closePicker()
}
I am Created 2 Views, One is and Used Protocol and Delegate. For first view the Delegate function is not called.
My FirstView Controller : Here I am Accessing the Delegate Function.
import UIKit
class NextViewController: UIViewController,DurationSelectDelegate {
//var secondController: DurationDel?
var secondController: DurationDel = DurationDel()
#IBAction func Next(sender : AnyObject)
{
let nextViewController = DurationDel(nibName: "DurationDel", bundle: nil)
self.navigationController.pushViewController(nextViewController, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
secondController.delegate=self
}
func DurationSelected() {
println("SUCCESS")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
My SecondView Controller : Here I Am creating Delegate.
import UIKit
protocol DurationSelectDelegate {
func DurationSelected()
}
class DurationDel: UIViewController {
var delegate: DurationSelectDelegate?
#IBAction func Previous(sender : AnyObject) {
//let game = DurationSelectDelegate()
delegate?.DurationSelected()
self.navigationController.popViewControllerAnimated(true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
To me, it looks like you're pushing a view controller that you haven't actually set the delegate for. If you change your "Next" function, to include the line
nextViewController.delegate = self
You should see that the delegation works. In doing this, you can also probably remove the creation of "secondController", as it looks like that's redundant.
The naming convention you have followed would confuse fellow developers in your team. The instance should have been
let durationDel = DurationDel(nibName: "DurationDel", bundle: nil)
And then as #Eagerod mentioned, the delegate you would set is
durationDel.delegate = self