bind arrayControlle to NSViewControllerr in Document-based cocoa app cause the NSViewControllerr init(code :) called many times - nsarraycontroller

I am develop a Document-based cocoa app use coredata,I bind NSViewController to NSArrayController like this :
https://developer.apple.com/library/archive/qa/qa1871/_index.html ,
,when I save some NSManagedObject in a document and then read data from the saved document,the models can read from the saved document,but the NSViewController be create many times,For example,if I saved 7 NSManagedObject in document,and then I open the saved document,I can get the saved 7 NSManagedObject,but the NSViewController will create 7 times,what should I do? thanks

I solved it, because my FUEAttributeVCBaseModelMO class has a attribute "#NSManaged public var owner: FUEAttributeViewController?",when I reopen the existed document,If the document has FUEAttributeVCBaseModelMOs,the object of FUEAttributeVCBaseModelMO will call the FUEAttributeViewController init.

Related

Swift class to interact with Interface Builder via IBOutlet

Good evening all,
I'm slowly working through my first OS X app. I have been having a hard time getting my Swift class to interact with an NSPopUpButton. Just to make sure I was doing it right, I created a new project and successfully erased all entries and entered text into the NSPopUpButton via AppDelegate. However, as soon as I try to move the same functionality to my own class, I can't even get the IBOutlet connection across to the new class.
Is a particular subclass type required of a new class to work properly with interface builder?
Here is a screenshot of the class I have created, as well as AppDelegate where I am trying to call the function belonging to this class.
Finally, here is the IB element in question, should I be able to select my own class under the 'Custom Class' inspector?
I am an iOS developer, but I would imagine the same principles would apply to your situation.
A ViewController class and an interface created in interface builder are two seperate things. While it may appear that they are connected via an iboutlet, they are actually independent and one can be instantiated without the other.
Currently, you are only creating an instance of your ViewController class in your App Delegate - and that's all. The system has no idea that your xib even exists! The outlets will only be connected once your app connects your xib to your ViewController class.
How do we do this? It's actually quite simple. Instead of instantiating our view controller like this:
let viewcontroller = ViewController()
We would connect our view controller to our xib in the instantiation:
let viewcontroller = ViewController(nibName: "MainWindow", bundle: NSBundle().mainBundle)
The nibName is telling the system the file name of your xib, and the NSBundle().mainBundle is telling the system where to look for the xib.
This will all only work if your xib has been assigned a custom class, like you mentioned. In your xib in interface builder, select the entire view controller. Then, in the custom class inspector type in the name of your ViewController class (in your case: ViewController - it should autocomplete). This will make sure your outlets are connected.
And you should be set up!! Let me know if you have any more problems come up.
Good luck!
EDIT:
This replaces the first part of my answer, however the part about hooking things up in Storyboard remains true. Upon reconsidering, I've believe I've realized that we are only creating the view controller, and not adding it to our view. Despite this, I believe we can take a short cut solution by adding one method to your view controller subclass (the one we set in the Storyboard). Start typing in viewDidLoad, and it should autocomplete. Type in super.viewDidLoad() at the beginning of the method. After that, type self.listUpdate(). This should work if the classes are hooked up correctly in Storyboard. This means you can delete the variables you created in the App Delegate.
Reference: You might also find Apple's documentation on creating a view controller handy (it's in Objective C online, but can be easily converted to Swift - it's the concept that counts): NSViewController Class Reference

Swift, storyboards and core data...a missing persistentstorecoordinator?

I am working on a new Cocoa project using Swift, Core Data and storyboards, and have come across a problem that makes no sense to me. After some fairly extensive hunting around, including on this site, I have come to the conclusion that I must be missing something obvious, but cannot figure out what. Here is what I have done so far:
1.Create a new project, Cocoa Application, using Swift, Storyboards, and Core Data.
2. Create an entity in the .xcdatamodeld. Let’s call it Dataset.
3. Create a subclass of NSSplitViewController (for what i want to do in the rest of the program).
4. Set the window content of the main window to and instance of myVC. I checked, and it loads up and displays fine.
5. In the viewController.swift, get the managedObjectContext like so:
#IBOutlet var moc:NSManagedObjectContext!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
let appDelegate = NSApplication.sharedApplication().delegate as AppDelegate
moc = appDelegate.managedObjectContext
println("mainsplitviewcontroller moc:")
println(moc)
println("mainsplitviewcontroller psc:")
println(moc.persistentStoreCoordinator)
NSLog("Main split view loaded")
}
(yes, I have about dependency injection, but I want to solve this problem first).
In IB, put a managedObjectContext object in the View Controller instance.
In IB, connect the myVC outlet for the variable moc to the managedObjectContext.
In IB, create an array controller. Set it To Entity. Entity Name is Dataset. Turn on Prepares Content.
Either as an outlet or a binding, connect the array controller to the MOC. Using outlet, just dragging from managed object context in it's right-click popup to the icon for the MOC created in 6 above. For bindings, the old fashioned way, going to the bindings tab, and under Parameters, Bind to: (view controller), Model Key Path: moc. (moc is from 5 above)
Then, I build and run. and I get the error: "Cannot perform operation since managed object context has no persistent store coordinator."
This happens whichever way I try to do 9, above.
Now, the thing is, from my println statements, the objects referred to in both the app delegate and the viewcontroller are the same, both for the managed object context and for the persistent store controller, as below:
appdelegate moc:
appdelegate psc:
mainsplitviewcontroller moc:
mainsplitviewcontroller psc:
I wish I could show images, but I am new here and so cannot do that. Am I doing something clearly wrong? I thought I understood the process: make sure the VC can access the MOC, then put the MOC object into the VC's window in IB, make it an outlet, and connect it to an array controller. Why would the swift file for the view controller seem to show that the PSC is the same as the app delegate, but in IB, the array controller think the MOC has no PSC at all?
Thanks for reading!
I don't know if this is going to help, but I'm not surprised that your project shows that error. You have two managed object contexts - one created by your app delegate, and one created by the storyboard. Your interface code is connecting to that second MOC, which is not connected to your persistent store.

NSViewController in Swift - Can't unwrap Optional.None

On my main window I have a CustomView. Depending on what the user selects, this view will be changed. To have a clear source code, I created for each new view a NSViewController with a new xib file. Then I connected my IBOutlets to the new ViewControllers. This works perfect. But if I add an IBAction, Xcode says, that it cannot connect to the action. So I googled and I found out, that I should not connect all the IBOutlets and IBActions to the File's Owner of the ViewController. Instead I added a new NSObject to the new xib file and set the Class to my ViewController class. If I now want to access the IBOutlets, I'm getting the error fatal error: Can't unwrap Optional.None at the line, where I want to access the IBOutlet.
Any ideas? What's the right way to work with NSViewControllers. Do I have to add an NSObject? How many instances of my ViewController are then created?
"Can't unwrap Optional.None" is what happens when you have an implicitly unwrapped optional (one defined with an !) that is nil but you try to use it anyway. For example:
var aNumber : Int! = nil
aNumber + 5 //fatal error: Can't unwrap Optional.None
I believe outlets are declared as implicitly unwrapped by default in Swift, so you're probably getting this error by trying to do something with an outlet that isn't connected in interface builder (or your storyboard or whatever).
As to the rest, it's really hard to understand what you're doing in your app. I understand you have an NSViewController for each view, but what outlets are you connecting to them? Where are you adding the IBAction? Which file's owner do you mean, the owner of the window's nib? The owner of your NSViewControllers?
It sounds to me like you're making this way too complicated, and adding more NSObjects to the mix is almost certainly the wrong way to go. See if you can simplify things or upload your project someplace so we can take a look and better diagnose your issue.
I now have the solution. Here is the way to use NSViewController: (working in Beta 3)
Create a new app and add a CustomView to the main window. Connect this custom view to your AppDelegate.
Add this var to your AppDelegate: var mainViewController: NSViewController?
Create some new Swift Cocoa Classes as Subclasses of NSViewController and check "Also create XIB file for user interface" as much as you need.
For each ViewController add a new variable to AppDelegate like this: var firstVC = firstViewController(nibName: "firstViewController", bundle: nil)
Now edit your new xib files and connect everything to the correspondig swift file.
For changing the view and the view controller, choose this code:
mainViewController?.view.removeFromSuperview()
mainViewController = firstVC //or the vc you need
customView.addSubview(mainViewController?.view)
mainViewController?.view.setFrameSize(customView.bounds.size)
That's all. All IBActions and IBOutlets now work without any error. If you need a method for doing some things on loading the view, take override func loadView() { super.loadView() ...

Proper way to hook up a NSTextField

I am trying to create a simple Mac OS X application which displays text output, which is logging for my program. Here is what I did:
1) Created a Mac OS X UI project
2) Added a "Text Field" component into the middle of the Application window in MainMenu.xib
3) Added a new class "MainWindow.m" with the following property:
#property (assign) IBOutlet NSTextField *mainWindowText;
4) Connected up a "Referencing Outlet" from the text field component to the property. I now see a gray dot to the left of the above line of code
5) In my application, I create a new thread which creates an instance of MainWindow. Then I wait 5 seconds and try to access the mainWindowText variable above but it is always null. I was expecting a non-null variable so I could call setStringValue: and modify the text at any time.
I tried doing something similar with doText: and I am able to see the callback when I hit enter, and write text there. However I need a way to modify the text at an arbitrary time and I thought the above property was the proper way.
I have also tried adding a #synthesize statement, but that had no effect.
Any suggestions?
Update: After reading some posts I think the problem is that I am working with the wrong mainWindow object. I tried creating a NSObject in the NIB and making its custom class type mainWindow, and created a IBOutlet (type MainWindow *) in one of my other classes, but it would not let me wire these two things up, so I am not sure how to access this NSObject object I added to the NIB.
The NIB file has an owner - that is the class that you want to use to do this stuff. The way things should work is:
Create an instance of your class (the owner, with the outlet)
During initialisation this class loads the NIB file
As the NIB file is loaded the outlet references are configured
A callback fires (awakeFromNib) to tell the owner all config is done
After that's complete, then you can access the outlets.
From the initial project you should have a NIB file and a class that is its owner so you should use that to do your controlling tasks (certainly until you have more experience with NIB archives).

Can I use NSViewController to provide a reusable NSTableView with defined columns and data?

I'm fairly new to Xcode and Cocoa development, so please excuse me if I use the wrong terminology.
I have a window which has an NSTableView bound to a NSArrayController. The NSTableView has some predefined columns and the NSArrayController is populated with data when my window is loaded.
This all works fine, but I now need to re-use the functionality in a number of other windows.
After much reading I think and NSViewController is what I need, to provide an object that I can re-use in different windows in multiple .xib.
So what I have done is created a new NSViewController sub class in Xcode which also created a new xib for that controller.
The xib contains a custom view, where I have placed my NSTableView.
#interface KeyViewController : NSViewController
#property (weak) IBOutlet NSTableView *keyTable;
#end
The files owner class is set to the KeyViewController, and the view outlet is set to the files owner.
I then placed a ViewController object into the original window and hooked up the view to a new custom view in the window
I then set the nib name for the ViewController in its properties.
The new view never gets displayed and the view controller initWithNibName never gets called.
Am I missing something vital or missing the plot completely. Should you be able to do this just with interface builder or do I need to alloc and init the view in code?
If I do have to do it in code, whats the purpose of the ViewController object in IB and the Nib Name property for it?
Thanks..

Resources