0
votes

Summary of what Im trying to do.

I have a NSMutableString property called mailText in my AppDelegate.h, whenever I change the value of this property, I want my viewController to be notified and it will set the value of its local IBOutlet property to the new value. Eventually, APpDelegate will change the string based on a received Push Notification.

In order to test, I am firing a timer in my APpDelegate and changing the value of mailText at timer expiry. However, the addObserver method in my ViewCOntroller is not being called when this happens

Code in my AppDelegate.h

@property (strong, nonatomic) NSMutableString *mailText;

Code in AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    ......

    self.mailText = [NSMutableString string] ;
    self.mailText = (NSMutableString *)@"First text" ;

    [self enableTimer] ;
    ......
}

-(void) enableTimer
{
    NSTimer *timer = nil ;

    timer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(updateText) userInfo:nil repeats:NO] ;

    //self.myTimer = timer ;

}

-(void) updateText
{
    self.mailText = (NSMutableString *)@"Changed to second text..aaanjanalnal .. jansjanskanska" ;
    NSLog(@"Timer fired...updating mailtext") ;

}

Observation: The NSLog "Timer fired..." is being printed when I run the app on simulator

Code in my ViewController.h

@interface MailDispViewController : UIViewController

@property (weak, nonatomic) IBOutlet UITextView *mailDispText;

@end

Code in my ViewController.m

Within

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    [(AppDelegate *)[[UIApplication sharedApplication] delegate] addObserver:self forKeyPath:@"mailText" options:NSKeyValueObservingOptionNew context:nil];
}

Within

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    NSLog(@"received a KVO") ;

    if ([keyPath isEqual:@"mailText"]) {
        NSLog(@"received a KVO for mailtext") ;
        self.mailDispText.text = [change objectForKey:NSKeyValueChangeNewKey];

     }
    /*
     Be sure to call the superclass's implementation *if it implements it*.
     NSObject does not implement the method.
     */
    [super observeValueForKeyPath:keyPath
                         ofObject:object
                           change:change
                          context:context];
 }

Observation: Neither NSLogs "received a KVO" is not being printed.

Can anyone let me know what Im doing wrong?

A second question, how do I find the value stored in mailText from the debug window in Xcode. I tried po mailText, but that did not work.

2
Found the issue...viewDidLoad was not called.. - ArvindSN
Put a log in your -viewDidLoad. Is it happening before the timer is firing? By the way: you should basically never use a mutable type for a property; value properties should almost always be copy instead of strong; you can't just cast string literals to NSMutableString* and expect that to make them mutable; assigning [NSMutableString string] to the property immediately before assigning another value does nothing but was cycles. - Ken Thomases
Thanks Ken. I think your answer explains the next issue I am seeing (crash when I come back to main screen). Could you please explain the part about mutable string in beginners terms? I am new to ObjectiveC and all this Mutable stuff is new to me since I was mainly a C programmer before. When I tried to use NSString, I got a EXC_BAD_ACCESS, when I tried to change the value after timer expiry. So, how do I change value of string this if I cannot use NSMutableString - ArvindSN
Update: Changed everything to NSSTring. Still hitting same issue. If I click on second table cell in main view & segue into the textview and then come back, there is a EXC_BAD_ACCESS when the timer expires and NSString is being overridden. One Q: Do I need to have a navigation controller in between the initial Navigation Controller-->Table View Controller and my ViewController with TextView? - ArvindSN

2 Answers

0
votes

The answer is: Do not call

[super observeValueForKeyPath:keyPath
                         ofObject:object
                           change:change
                          context:context];

when super will not handle the keyPath. It means that whenever they key path is yours or the context is yours you should not call super. Only call super to ensure kvo not from your code can be observed regularly.

0
votes

Found the issue: the viewDidLoad of MailDispViewController was never called since I never segued into this view.