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.
Related
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()
I have a viewmodel tied to a view used in a region. I'm trying to find a way that when that view is navigated to from a particular view (say view A), it does some work internally, like initializing some lists, setting some stuff, whatever. But if it has been navigated to from view B, it needs to NOT reinitialize everything, and just display the data it already has.
I could pass a parameter I suppose, saying whether this is a new operation or if we are going back to work on the old one, but I thought it would be nicer to be able to state that if we came from this view, we do one thing, and if we came from that one we do another.
If that makes sense :)
You can implement the INavigationAware interface which contains 3 methods. One of these methods is the OnNavigatedTo method. There you can access the journal and check the current entry. From there you should be able to determine if it came from View A or View B.
public void OnNavigatedTo(NavigationContext navigationContext)
{
var journal = navigationContext.NavigationService.Journal;
//use journal.CurrentEntry
}
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;
}
I am using NSTreeController with NSOutlineController to display contents in 1parent-1child hierarchy.
My structure is like this:
- parent
- child
- parent
- child
Now when user press a refresh button, I want to remove all the nodes and refill it again.
[[treeController arrangedObjects] removeAllItems];
[[treeController arrangedObjects] removeAllObjects];
but nothings seems to be working.
I guess binging NSTreeController with NSArrayController should help but I really don't know steps to bind -NSArrayController-NSTreeController-NSOutlineController.
I do it all the time with unbound lists.
Simple to clear the list:
[treeController setContent:nil];
From the documentation for the content property:
The value of this property can be an array of objects, or a single root object. The default value is nil.
If your content is an array (presumably an NSMutableArray), then
[treeController.content removeAllObjects];
would be appropriate. Setting it to nil removes the underlying container. If your content is a single object, then
treeController.content = nil;
is the correct choice.
I have to implement an Form View, or in other words: A class that is used to put a complex input form on the screen.
The Form is built up of FormComponents. There is an addFormComponent() Method to compose the form with these. And then, the form has an isValid() Method which will go through all the FormComponents and check their associated FormValidators.
For sure this thing has a lot of "intelligence", but most of this is just a call to some other class. For example the isValid() method does cool stuff, but it really only calls the isValid() methods of the FormComponents which are registered in an array. Nothing too fancy.
Well, that beeing said, must I make a fat FormViewController for this, or is an View just fine?
My understanding of these is, that a ViewController is used when there's some big logic involved. In this case, the Form View has a template which will simply iterate over the FormComponents and include them. Each FormComponent has it's own template in turn and does it's own stuff.
I've always been struggling with ViewController and View and I think I'll keep on doing that until I get a nice R.I.P. brick... but maybe someone can clear this up a little bit ;-)
The purist in me is saying that this belongs in a ViewController. I guess maybe it would depend on the framework you are using. For example, this type of setup would be very easily implemented in a Spring Controller object. It sounds like creating a controller in your case would be a lot of extra work.
Nothing is ever set in stone. You can implement in the View for now and if this turns out to be a huge burdon, move it to a Controller class. Knowing when to refactor is the difficult part.