Updating a UILabel from another view using NSNotificationCenter - objective-c

I'm updating a UILabel in another view using a method invoked using the NSNotification center.
What I'm finding is that it's not working, the label remains unchanged until the view is reloaded at a later point (not using the method called by nsnotification center).
The label is set to nonatomic, retain and I'm using self to bind everything to that property.
obviously all of the code (the method) that tries to update the label is located in the corresponding viewController. The method gets called (I can see that with NSLog), and all it does is self.label2.text = #"label 2 updated";
I'm able to update the text value of the label using a timer just fine, so I don't think there is a problem with the label, but rather with my understanding of threading and/or what is loaded or not at a given time.
What do you think is the problem?
PS: i WILL chose an answer even if it doesn't help me that much, so please post your wildest guesses!

First make sure that your label is not nil when you set the text.
If it's not nil, try calling setNeedsLayout on your label after setting the text (this shouldn't be necessary). Also, verify that you are on the main thread with:
[NSThread isMainThread]
If that doesn't help, use a subclass of UILabel, override setText and put a breakpoint on it to see what's going on.

Related

NSTextField will not update

[self.change setStringValue:[NSString stringWithFormat:#"%i", changeValue]];
where change is an IBOutlet of type NSTextField. For whatever reason I can not get the text field to display anything I want. Every time I run, the field is "0". Any ideas on why it won't change?
Never update textfield or pop-button in init. You have to fill default values in awakeFromNib or some other delegates once class gets initialized.
Ok here is the embarrassing rookie mistake for others to learn from. I was calling my setstringvalue before the view was even loaded; in the didfinishlaunching method. Use the awakefromnib method to make sure you view is loaded. Via Apple:
Finally, after all the objects are fully initialized, each receives an awakeFromNib message.
Verify that the outlet is really linked with the NSTextField you have put in the xib file.

Why is my outlet nil?

I'm having trouble with a cocoa project. I'm displaying a keyboard composed of NSButtons, and I'd like that when I click on one of the keys, the label is added to a NSTextField. I have a controller that I use as a singleton, so each key "knows" how to access the controller. In the controller, I have an outlet linked to the NSTextField. When I click on a key, nothing happens. So I used something like NSLog(#"%#", [[[OakController] sharedInstance] textarea]) on a mouseDown event, and in the console output, I get (null).
Long story short, my outlet is set to nil, and I don't know why it is that way, or how to solve that...
Here's the code of the controller : https://gist.github.com/1090564. Sorry for the lack of syntax coloring.
Thanks for reading guys!
My guess is that you actually have multiple instances of OakController instead of one like you expect. Did you drag a blue cube into your IB document and change its custom class to OakController? That will allocate and initialize a new object each time. I'd guess that your sharedInstance method also allocates and initializes an instance.
Try adding an awakeFromNib method to OakController, and add a break point. Log self's pointer value. In your second case were the outlet is unexpectedly nil, also log self's pointer address.

Using NSProgressIndicator inside an NSMenuItem

I'm trying to use a NSProgressIndicator (indeterminate) inside of a statusbar-menu. I'm using an NSView-object as view for the menuitem, and then subviews the progress indicator to display it. But whenever i try to call the startAnimation: for the progress, nothing happens. When i try do the very same thing on a normal NSWindow it works perfectly, just not when inside a menuitem.
I'm new to both cocoa and objective-c so I might've overlooked something "obvious" but I've searched quite a bit for a workaround but without success. I found something about menuitems cant be updated while shown and that you need to use a bordeless window instead. But I have not been able to confirm this in any documentation.
Edit:
Ok, almost works now. When using the setUsesThreadedAnimation: and from a MenuDelegate's menuWillOpen and creating a new thread. This thread runs a local method:
-(void) doWork(NSProgressIndicator*) p{
[p startAnimation:self];
}
This will start the progressindicator on a random(?) basis when opening the menu. If I call startAnimation: directly without going through doWork: (still using a new thread), it never works. Doesn't setUsesThreadedAnimation: make the progress-bar create it's own thread for the animation?
Solved it by using:
[progressIndicator performSelector:#selector(startAnimation:)
withObject:self
afterDelay:0.0
inModes:[NSArray
arrayWithObject:NSEventTrackingRunLoopMode]];
Inside the menuWillOpen:, the problem seems to have been calling startAnimation: before the progressbar was finished drawing itself.
How are you referencing the NSProgressIndicator that is in the view (and the one in the window, for that matter)? For example, do you have a controller class that has IBOutlet's hooked up to the progress indicators? If you are using an IBOutlet, are you sure it's hooked up properly in the nib file?
Also, where and when are you calling startAnimation:? (We need to see some code).
One thing that can sometimes happen is that you forget to hook up an IBOutlet in the nib. Then, when you attempt to tell the object to do something in code at runtime, the IBOutlet is nil, and so what you think is a message being sent to your object is in fact, a message being sent to nil. In other words, it's just ignored, and effectively looks like it's not working.
Provided you do have a (potentially) valid reference to the UI object, the other common issue you'll see is when a developer is trying to send a message to the object at "too early" of a time. In general, init methods are too early in the controller object's lifetime to be able to send messages to user interface objects—those IBOutlet's are still nil. By the time -awakeFromNib is called, IBOutlet's should be valid (provided you hooked them up in IB) and you can then send the message to the UI object.
Have you told it to use threaded animation via -setUsesThreadedAnimation:?

NSCFString or UIViewController?

I am using UIViewController (a subclass of course) with a text field which sends an action when the contents changed (to the contentsChanged: selector of the ViewController). It is done by sending contentsChanged: to file's owner in IB.
But when I test it, it says : "-[NSCFString contentsChanged:] : unrecognised selector sent to instance " and the instance pointer in hex.
I am guessing that for some reason the view controller gets moved to another pointer and a string gets allocated there, but I cannot figure why.
Any ideas ?
Sounds like a classic case. Read up on NSZombieEnabled for how to track this sort of problem down.
I have the exact same problem with a subclass of UIViewController and this piece of innocuous code:
- (void)viewDidLoad
{
NSLog(#"%# %s %#", [self class], _cmd, answerButton);
[self.answerButton addTarget:self
action:#selector(getAnswerToQuestion:)
forControlEvents:UIControlEventTouchUpInside];
}
Yes, answerButton is connected (it's an IBOutlet), yes, - (IBAction)getAnswerToQuestion:(id)sender; is a proper method, but no joy. When I commented out the viewDidLoad and made the connection in IB, it showed in the crash report that the failure happens on [UIControl sendAction:to:forEvent:] resulting in
objc_msgSend() selector name: performSelector:withObject:withObject:
I can't prove it, but I suspect there's a bug somewhere in the UIKit that translates the bindings and addTarget to a call to performSelector. I'm planning to upgrade to iOS 4.01 first to see if that won't solve the problem.
UPDATE:
I'm not sure anymore that my problem really is similar to Alexandre Cassagne's but in the interest of sharing information I will not delete it just yet. I solved my problem, as so often, when I started to make an example project in order to file a bug report. Yes, clicking made answerButton call getAnswerToQuestion: like a good little object and all was fine.
The difference between the subclassed UIViewController of the example project and that of my real project was that the first also functioned as the xib's File's Owner while the second was just one of several view controller. When I moved getAnswerToQuestion: to the File's Owner in my real project, clicking answerButton worked as expected. So, my hunch that the problem lay somewhere in the translation from binding to performSelector wasn't that far off: the problem lies in the Responder Chain. I would think that establishing the Action-Target link either programmatically or in IB would bypass the Responder Chain, but apparently not.
The problem now, of course, is that Alexandre states in his question that his contentsChanged: method already is part of the File's Owner, which makes my answer irrelevant to the question.
without looking at the code, it looks like you are calling contentsChanged: on the text field's text, instead of the UIViewController subclass.
you should consider using the UITextFieldDelegate protocol to get called back when the text of a UITextField changes. I have not looked, but this is the thing I would do off the top of my head.

3 notifications instead of one

I'm developing simple MVC app in Cocoa/Objective-C. I have a strange issue (or misunderstanding) with notifications and KVO.
I have AppController object in MainMenu.xib, hence I implement awakeFromNib method where I register for NSImageView changing its image property. I add self as an observer in the following way:
// options:3 equals to new/old passed values in changeDictionary
[backgroundImageView addObserver:self
forKeyPath:#"image"
options:3
context:NULL];
The backgroundImageView is an IBOutlet in AppController connected to NSImageView.
In standard observeValueForKeyPath:ofObject:change:context method I just log the received notification.
Problem is - when i change the image value of NSImageView I get 3 notifications instead of one. Can you help me with this? Maybe I'm overlooking something in options or in generally registering observer?
UPDATE: backgroundImageView is the instance of BackgroundImageView class which is sublcass of NSImageView. I subclassed the latter one for handling drag and drop operations as drag destination. When performDragOperation: is called (the last 'state' of the dragging) it changes the value for image property with setImage between willChangeValueForKey and didChangeValueForKey.
… it changes the value for image property with setImage between willChangeValueForKey and didChangeValueForKey.
When you send an accessor message, you get KVO notifications for free with it. You should remove the {will,did}ChangeValueForKey: messages, because they're the cause of at least one of the extraneous change notifications.
Is your AppController the File's Owner of two other nibs? If so, it'll receive an awakeFromNib message for each of those, too. MainMenu plus two makes three awakeFromNib messages, which means you'll add yourself as an observer three times.
There does not seem to be any obvious problem with setting of the observer.
Have a look at how you update the image that you observe, maybe it's being modified 3 times?