6

I need my app to pass the value of a variable myVariable from a class firstClass to another secondClass only when the variable changed its value. To do so, I thought of using the willSet property. Though, in Swift, you can't use it after the declaration of the variable.

class firstClass: NSObject {
    var myVariable = 0

    func myFunction {
       myVariable = 5
    }
}

class secondClass: NSObject {
    var otherClass = firstClass()
    // How do I retrive the value of the variable right after its value changed?
} 

I also thought of adding a NSNotification, but that wouldn't help because it doesn't pass a value. NSNotification only alerts about its changes.

 let myVariableNotification = NSNotification(name: "myVariableNotification", object: nil)

 class firstClass: NSObject {
    var myVariable = 0

    func myFunction {
       myVariable = 5 
       notificationCenter.postNotification(myVariableNotification)
    }
}

class secondClass: NSObject {
    var otherClass = firstClass()
       NSNotificationCenter.defaultCenter().addObserverForName("myVariableNotification", 
         object: nil, 
         queue: NSOperationQueue.mainQueue()
         usingBlock: { notification in
         println("The variable has been updated!")
       })
}

I seem to find no way to pass a variable once that variable changed its value. How can I do that?

Cesare
  • 9,139
  • 16
  • 78
  • 130
  • You want to pass value when navigating from 1st viewcontroller to 2nd or only when there is a change in value of that variable? – Arun Gupta Apr 20 '15 at 17:15
  • Thanks for your comment! Only when `myVariable` changed its value. Thanks! – Cesare Apr 20 '15 at 17:15

2 Answers2

8

You should use delegate protocols. For more information check out this document.

Set up a protocol in the secondClass, right after the import statements, like so:

protocol InformingDelegate {
    func valueChanged() -> CGFloat
}

Inside the same secondClass create a delegate variable (some suggest that it should be marked as weak):

var delegate: InformingDelegate?

Then, create some method in which you will access the changed value. You can assign it to value for example:

func callFromOtherClass() {
    value = self.delegate?.valueChanged()
}

This is it for the secondClass. Now onto the firstClass.
Here you only need to conform to the protocol by adding InformingDelegate after the class definition, like this:

class firstClass: UIViewController, InformingDelegate {
    ...
}

Then, inform the compiler that you are going to be a delegate for the other class by creating its instance, and setting yourself to be the delegate:

var secondVC : secondClass = secondClass()
secondClass.delegate = self
secondClass.callFromOtherClass() // This will call the method in the secondClass  
// which will then ask its delegate to trigger a method valueChanged() -   
// Who is the delegate? Well, your firstClass, so you better implement  
// this method!

The last thing is to actually conform to the protocol by implementing its method:

func valueChanged() -> CGFloat {
    return myVariable // which is 5 in your case (value taken from a question)
}

This will assign myVariable value (5 in this example) to the value in the other class.

Fengson
  • 4,751
  • 8
  • 37
  • 62
  • Thank you very much! Should I put `var delegate: InformingDelegate?` in the first or second class? – Cesare Apr 20 '15 at 17:40
  • You create a protocol, and a var "delegate" in the class that will retrieve the value. Then you set the other class (the one which will implement the method and set the value) as a delegate of this protocol by assing InformingDelegate to the class definition. – Fengson Apr 20 '15 at 17:42
  • Thanks! Where should `protocols` be put in? Outside the class? – Cesare Apr 20 '15 at 17:45
  • 1
    protocol definition should be put above the class definition, right after import statements :) – Fengson Apr 20 '15 at 17:47
  • Working on it right now. I can't thank you enough for the effort you put in writing this :-) Thanks! – Cesare Apr 20 '15 at 17:57
  • Delegates are not the easiest to understand, but after you get the idea, you'll find that you can use them in multiple situations and the time you put into learning them is definitely worth it. – Fengson Apr 20 '15 at 18:00
  • @Fengson you rock! thanks for the effort to write this mini-tutorial – xhinoda Jun 30 '17 at 15:13
2

Best way to program this would be using NSNotification. Add a observer in your 2nd viewcontroller to listen for change in value of this variable. In 1st viewcontroller whenever this variable changes value post a notification to observer which 2nd viewcontroller is listening to.

You'll have to use the "userInfo" variant and pass a NSDictionary object that contains the value of myVariable:

NSDictionary* userInfo = @{@"myVariable": @(myVariable)};
NSNotificationCenter *notifying = [NSNotificationCenter defaultCenter];
[notifying postNotificationName:@"myVariableNotification" object:self userInfo:userInfo];

In your second viewcontroler which calls your notification center method set the notification and its calling method as below:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeInValue:) name:@"myVariableNotification" object:nil];

Calling method:

-(void) changeInValue:(NSNotification*)notification
{
    if ([notification.name isEqualToString:@"myVariableNotification"])
        {
            NSDictionary* userInfo = notification.userInfo;
            NSNumber* myVariable = (NSNumber*)userInfo[@"myVariable"];
            NSLog (@"Successfully received test notification! %i", myVariable.intValue);
        }
}
Arun Gupta
  • 2,628
  • 1
  • 20
  • 37
  • Thanks for your answer! Does `NSNotification` pass a value? I used it but it only alerts about the changes of a variable. Please check my edited question. I added the code I'm using to declare and set up a `NSNotification`. Could you please show some code? Thanks! – Cesare Apr 20 '15 at 17:24
  • Will that variable always be integer returning? – Arun Gupta Apr 20 '15 at 17:32