NSNotificationCenter in document-based app - macos

I'm using NSNotificationCenter to send custom notifications in a document-based app.
A document-based app can have many open documents. Ideally, I would like the the document and its children to receive only the notifications created within the document or its children. In other words, a document should receive only the notifications that the same document generates.
At first I thought I could use the notificationSender parameter of addObserver:selector:name:object: but then I realised that I don't always know which object will send the notification.
Do I have to check if I'm in the right document for every custom notification? Is there a better way to do this?

I think that your approach works if you use the main document as notificationSender argument for both addObserver:selector:name:object: and postNotificationName:object:.

You can define a NotificationCenter in your NSDocument class and use that to post notifications within a document (Swift):
class Document: NSDocument {
let notificationCenter = NotificationCenter()
// Other stuff
}
And call it like this:
document.notificationCenter.post(name: yourNotificationIdentifier, object: nil)

Related

XCode: link to instance function in comment

I'm trying to add some documentation to my project, and I was wondering if it's possible to add a "link" to an instance function in another class within a comment. Right now I can simply have something like // see AppDelegate for the response to this notification and I can command-click on AppDelegate to take me to that file, but I'd like to be able to command-click and be taken to a specific function where exactly something like a notification is responded to.
Is this possible?

Change UILabel from appDelegate

I want to do some stuff from the appDelegate in Xcode. One of these things are to change a UILabel.
ViewController *viewController = [[UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"id"];
viewController.label.text = #"heeej";
I was told this would do the trick. Doesn't work. Label doesn't change. Does anyone know what the problem is?
There are several problems:
Don't do anything in the AppDelegate except for loading the window an the initial view controllers (if needed).
You are instantiating a new view controller in the first line. I assume you already have a view controller and you want to change the label in that view controller. Than you need a reference to that view controller and use this reference to send messages to it.
The label should not be a property of the view controller. You should try to follow the design pattern Model-View-Controller or the pattern Model-View-ViewModel. Ask you preferred search engine what those are if you don't know.
id as an identifier for anything in Objective-C is a bad idea because this is used as an object type.
Edit: You don't need a reference to change a property in the view controller. Use notifications to update the label. The system sends a notification with the name UIApplicationWillEnterForgroundNotification' (see [here][1]). Add the view controller as an observer to the[NSNotificationCenter defaultCenter]` for this name and react on the notification. Read the Apple documentation if you don't know what I am talking about.

Disabling a view in cappuccino

How can I disable a CPView? (so that the user can't interact with it while it's still visible)
It's useful for example when the user clicks on something that sends a request to the server and it should get disabled till the result comes back.
CPControls (as abstract subclass of CPView) contains a -setEnabled: method which most UI components inherit from.
http://cappuccino.org/learn/documentation/interface_c_p_control.html#a68d3dc4f2d0a4fad8699fd5982cddc2d
CPViews do not contain such a method, so in your CPView subclass you need to write your own method for enabling and disabling. Then override -mouseDown: and whatever else you need to (look at the docs for CPResponder for a complete list) and implement like so:
- (void)mouseDown:(id)sender
{
if ([self isEnabled])
[super mouseDown:sender];
}

reference between app controller and window controllers

at the risk of a public flogging, I was hoping someone could clarify my understanding of communicating between the app controller and a window controller. Here is the scenario using xcode4.
using the default AppDelegate.h and .m as the "controller" (which is also a delegate to MainMenu.xib). Have an ivar called int counter.
Created page.xib and PageController.h and .m (subclass NSWindowController). Imported it into AppDelegate.m
Used IBAction to create and view the page object. Like this:
if (!page1) {
PageController *page1 = [[Page
if (!page1) {
page1 = [[PageControoer alloc] initWithWindowNibName:#"page"];
}
[page1 showWindow:sender];
So the new window pops and we can press buttons, etc. The code for the new window is all in PageController.h and .m. and things basically work.
That is the context, here is where I'm confused.
a) question: let's say I want to access that original ivar in AppDelegate.h called counter from PageController. Either retrieving or updating the variable. What approach would I take?
b) confirm: let's say I'm back in the AppDelegate and want to get access to a selector from page1. I believe I can do this as so: [page1 runaction]; or [[page1 variable] setStringValue:#"hello"];
(this complies but I'm not sure it really works because I can't get the changes into the xib view.)
ok and the stumper. Say another view was created with another view controller call it Page2Controller.h and .m.
c) how should data flow between page and page2 -> via the AppDelegate or directly? what would the syntax look like to connect them together?
I've been following tutorials, but they don't really cover this back and forth messaging. Thanks for all the help!
a) Generally, if you want to have data that is accessed by your controllers, it should be in a model which they are given access to in some way. You can access things in the app delegate using this method:
AppDelegate* appDelegate = [[NSApplication sharedApplication] delegate];
[appDelegate <some method>];
b) I don't understand what you're asking. If the app delegate has a pointer to page1, then yes, you can call it directly.
c) Again, you should have a data model of some sort. The controllers should update the data model when the user changes the view. You can use notifications, IBActions, and direct calls to do the updating, for example. You should look up the Model, View, Controller design pattern.

Prefill email content with NSButton hyperlink

I was wondering how I could, or if it's even possible to, prefill an email message's content when you click an NSButton, so far I open up the default email client but I want to prefill the body of the email and was wondering how I'd do that. Below is the current code:
-(IBAction)openEmail:(id)sender {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:#"mailto:domain#domain.com"]];
}
The "mailto" URI scheme supports this: http://en.wikipedia.org/wiki/Mailto
Send email
Rather than forcing a user out of your app, why don't you use MFMailComposeViewController to present the standard message composition window?
MFMailComposeViewController conveniently also has methods to set the message body and just about anything else you would like.
UPDATE: Oops, I misread "NSButton" as "UIButton" - what I wrote above only applies to iOS. Using the mailto: additions is the correct approach AFAIK on OS X.

Resources