What is the purpose of the NSMenuItem's tag attribute? - cocoa

Can I use the item's tag attribute to store a special key/ID or is it meant for something else?
Example of intended use:
- (void)awakeFromNib {
[self.popup addItemWithTitle: [NSString stringWithFormat: #"dummy title" ]];
[[self.popup lastItem] setTag: 1658 ];
}
- (IBAction)popupAction: (id)sender {
[self someMethod: [sender selectedItem].tag];
}

yeah the tag of all controls is free for your devious use, you may use different numbers for different items, or to identify them as a kind of item, it is up to you.

As the documentation says:
You typically assign tags to menu items from Interface Builder, but you can also assign them programmatically using the setTag: method of NSMenuItem.
For further details, read the Application Menus and Pop-Up Lists and User Interface Validation guides. But the basic idea is that Cocoa doesn't care what you put there.
I believe the intended purpose is to let you loosely couple parts of your code together—the code that validates user actions doesn't have to know how your interface is designed, and your interface doesn't have to know anything about the validator; they just have to agree on a number. However, in modern Cocoa, it's just as easy, and even more loose, to just look at the action, so the tag is freed up for anything you want.

Related

How to use NSObjectController and Managed Object Context using Cocoa Bindings

Searched entire Internet but couldn’t find the modern solution for my problem.
I want to use NSObjectController in pair with Core Data through Cocoa Bindings and struggle to set it up properly. Worth noting that I’m using latest version of Xcode and Swift.
What I’ve done:
For testing purposes I’ve done the following:
Created an macOS app with “Use Core Data” option selected (the app is not document based);
Dragged 2 NSTextFields into the Storyboard Dragged NSObjectController to the view controller scene;
Added Employee Entity to Core Data model with 2 attributes “name” and “surname”;
Done everything from the answer in How do I bind my Array Controller to my core data model?
Set NSObjectController to entity mode and typed in “Employee”,
Prepares Content selected, Use Lazy Fetching selected so all three options checked;
Binded the NSObjectController’s Managed Object Context in bindings inspector to the View Controller’s managedObjectContext;
Binded NSTextFields as follows: Value - Object Controller, Controller key - selection, Model Key Path - name (for 1st text field) and surname (for 2nd).
That’s it.
First set of questions: What I did wrong and how to fix it if it’s not completely wrong approach?
I’ve read in some post on stackoverflow that doing it that way allows automatic saving and fetching from Core Data model. That’s why I assumed it should work.
So here is a Second set of questions:
Is it true?
If it is then why text fields are not filled when view is displayed?
If it is not then how to achieve it if possible (trying to write as less code as possible)?
Third question: If I used approach that is completely wrong would someone help me to connect Core Data and NSObjectController using Cocoa bindings and show me the way of doing so with as less code written as possible using the right approach?
Taking into account that there no fresh posts about this topic in the wilds I think the right answer could help a lot of people that are developing a macOS app.
Thanks in advance!
I think your basic approach is correct, although it is important to understand that you need a real object, an instance, in order for it to work.
Creating a NSManagedObject subclass is generally desirable, and is almost always done in a real project, so you can define and use properties. You can do it easily nowadays by selecting the data model in Xcode's Project Navigator and clicking in the menu: Editor > Create NSManagedObject Subclass…. Technically it is not necessary, and in a demo or proof-of-concept, you often muddle through with NSManagedObject.
Assuming you are using the Xcode project template as you described, wherein AppDelegate has a property managedObjectContext, the following function in your AppDelegate class will maintain, creating when necessary, and return, what I call a singular object – an object of a particular entity, in this case Employee, which your app requires there to be one and only one of in the store.
#discardableResult func singularEmployee() -> NSManagedObject? {
var singularEmployee: NSManagedObject? = nil
let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest(entityName: "Employee")
let objects = try? self.managedObjectContext.fetch(fetchRequest)
singularEmployee = objects?.first
if singularEmployee == nil {
singularEmployee = NSEntityDescription.insertNewObject(forEntityName: "Employee", into: self.managedObjectContext)
}
return singularEmployee
}
Then, add this line of code to applicationDidFinishLaunching
singularEmployee()

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];
}

What exactly is an NSTreeController's "arrangedObjects"?

I'm trying to bind an NSTreeController's "arrangedObjects" to a custom view's "managedContent" (so that it can show a custom outline, for instance). In the setter...
- (void)setManagedContent:(NSArray *)newManagedContentArray {
//code goes here
}
nothing ends up working since newManagedContentArray ("arrangedObjects") apparently isn't an NSArray (and therefore I can't addObject: etc. etc.) Instead it's showing up as an NSControllerTreeProxy. My question is, what exactly is "arrangedObjects" supposed to be? Am I supposed to bind to it? If so, how?
arrangedObjects isn't supposed to be an array for NSTreeController. It states this quite clearly in the documentation. What you do get is the proxy object you are seeing, which you can use the childNodes and descendantNodeAtIndexPath: method on to get your tree structure.

Is there any benefit of having (id)sender in IBAction

When coding with cocoa I've noticed that it's not necessary to have sender parameter when defining IBAction, hence following action:
- (IBAction)showUserInfo:(id)sender;
can be declared as
- (IBAction)showUserInfo;
So I'm wondering if there is any other benefit besides having the button/menu item that sent the action? Only other situation I can think of is having few objects calling same IBAction. Anything else?
Doc says,
The sender parameter usually identifies the control sending the action message (although it can be another object substituted by the actual sender). The idea behind this is similar to a return address on a postcard. The target can query the sender for more information if it needs to.
The sender parameter helps if you want any data from it. For example, on UISegmentControl value change, as in #Mark Adams answer. So if you don't want any information from the sender, you can just omit it, as in your - (IBAction)showUserInfo; example.
It can be handy to use the sender argument when you're connecting the method to UI objects whose values can change and you may need to work with.
For instance if I wired up a method to a UISegmentedControl and set it's control event to UIControlEventValueChanged, I can use the object passed as the sender: argument to obtain it's selected segment index and then, based on the value, make a change in the UI.
-(IBAction)segmentedControlValueChanged:(id)sender
{
UISegmentedControl *control = (UISegmentedControl *)sender;
// Show or hide views depending on the selected index of the segmented control.
if (control.selectedSegmentIndex == 0)
someView.hidden = YES;
else
someView.hidden = NO;
}

Resources