I'm having a difficult time understanding what's going wrong. I have an NSWindowController with a NSWindow and a NSTextView. I want to archive that NSWindowController and NSWindow (along with all of its controls) to a file.
Then, I want to unarchive that same NSWindowController and the NSWindow and all views from the file. But Apple docs say:
Note: Although the NSWindow class inherits the NSCoding protocol from NSResponder, the class does not support coding. Legacy support for archivers exists but its use is deprecated and may not work. Any attempt to archive or unarchive an NSWindow object using a keyed coding object raises an NSInvalidArgumentException exception.
Importantly, if I encodeWithObject:windowController, this doesn't store the NSWindow. Therefore, when I do decodeWithObject for the windowController, the NSWindow isn't loaded.
How do I archive/unarchive the NSWindowController / NSWindow and all of its controls? What am I missing?
Based on your answers, this is absolutely the wrong way to go about this. The only place an archived controller/view object graph makes sense is when it's archived as a nib/xib. A document contains data, not bits of the application's machinery.
If you're targeting anything below Lion, save your state somewhere in your document data when the document is saved and restore it when the document is loaded (see the various loading stages Document-Based Applications Overview for an understanding of where/when to do this).
If you're targeting Lion and above, the documentation isn't very detailed yet (and in some cases is completely nonexistent), but Lion supports EXACTLY this with very little effort on your part. See the WWDC 2011 videos, session 119 - Resume and Automatic Termination.
Related
I have a MacOS appkit app with a LOT of different NSWindows (hundreds), and they are each created from storyboards.
Many of these NSWindows have container views with complex embedded view/view controller hierarchies.
During initialization, it's necessary to know the model object associated with any given NSWindow, so its subviews and controls can be properly initialized. Since any NSController can know its NSView, and any NSView can know its NSWindow, it would be nice for that information to stored with the NSWindow.
It would be great to set a "representedObject" for the NSWindow, but unlike NSViewController, it doesn't really have one.
Is the only real solution to create a simple custom class (derived from a small base class) for each and every NSWindow storyboard object, so NSViews & NSViewControllers down the view hierarchy can get to my model data (pointer)?
A CLARIFICATION: very few of my NSWindow objects in our hundreds of storyboards have custom classes or code derived from NSWindow. So while a Category is definitely helpful for adding an API to classes to ACCESS the model data associated with the NSWindow, it's not helpful in creating a property or instance variable and initializing it in all those NSWindow storyboards.
ULTIMATELY I PRESENT A SIMPLE BUT DISGUSTINGLY BAD SOLUTION NO ONE SHOULD COPY:
Our app does not use NSDocument, which would provide a facility for associating NSWindow objects with a document/model architecture. So our goal has been to allow each and every NSController and NSView to get access to the appropriate singular document model object required to initialize the view's controls.
I've been warned by Apple engineering gurus that I cannot depend on the order in which views and subviews are created and initialized. That makes passing data down into complex storyboard embedded subviews tricky and error-prone.
But -- with all UI on the main thread, it is not possible for a single application on MacOS to create, initialize, and display one storyboard AND have another storyboard initialization & display interrupt that process (at least not our user-invoked application storyboards). So the simple solution is...
...to have a temporarily set application-level global with the desired document model pointer. That, and a stack-based lock count to insure that the above assumptions are never violated. Terrible design. Efficient solution.
No one needs to remind me WHY this is not good. But if there's a better solution it has escaped my testing. I found that even viewDidLoad and viewWillAppear can't be trusted to have a solid pointer back to its NSWindow...
Without knowing your application structure; you will need a mechanism to assign the model pointer to each individual window. This will necessitate adding some code somewhere. An NSWindow subclass does seem appropriate.
In the AppKit MVC pattern, model data usually fits between the view and the view controller. Attempting to associate the model with the window is fighting against this pattern to some extent.
That being said; the Objective C runtime does allow you to add custom properties to existing classes using categories. This is achieved using Associative References. The relevant functions are:
objc_setAssociatedObject
objc_getAssociatedObject
objc_removeAssociatedObjects
This article has a good rundown of the benefits and downsides of that approach.
I have studying how to use IKImageView in my app. I downloaded the following demo from Apple site.
https://developer.apple.com/library/mac/samplecode/IKImageViewDemo/Introduction/Intro.html#//apple_ref/doc/uid/DTS10004049
One thing I do not understand is: This project has only implemented a Controller class.
#interface Controller : NSObject
{
...
I do not understand how does it work at all. If I create a new project in XCode, it will usually generate an AppDelegate class which implements NSApplicationDelegate interface.
I do not know if I understand the mechanism correctly.
Does the following steps describe how it works?
1) In info.plist it specifies the main bundle is MainMenu.xib.
2) the Window is binded to the Controller like so
3) When the application starts, it loads the Windows from the MainMenu.xib and the Controller class takes over the windows interaction from there.
It's really old sample code. It predates Xcode project templates generating an app delegate for you.
Back then, early Xcode and ProjectBuilder (the old name for it)
Left it up to you to do that.
Lots of older sample code has this sort of thing. As long as things get kickstarted by nib loading, magic happens, objects are instantiated and connected
If you have a simple controller that inherits from NSObject and it has a proxy in you main nib file, it will get created. If you also connect its proxy as delegate to some view or control in the nib, all of that happens.
You don't technically need an object that is the delegate of you NSApplication object. But in reality it is a good best practice and any non trivial app will have that and a lot more.
There's a lot of magic that happens when the C function NSApplicationMain() is called at the launch of your app.
The old and in many ways out if date book Cocoa in a Nutshell covers this well.
Yeah you pretty much describe how it works and what it's doing.
It's relying on the fact that NSApplicationDelegate is an informal protocol and it doesn't declare that Controller conforms to it and is using the NIB to kick-start the app.
I am working with cocos2d and CoreData. I have imported "AppDelegate.h" but I can't create an object from it. I would think that all I would do is:
AppDelegate *delegate;
When I do this it get an error saying AppDelegate is not defined. The AppDelegate .h and .m files are next to the main file.
Also, when I try to write to a file I don't get an error but it does not write.
The boiler plate code created by XCode (I'm assuming you are using XCode) will create an NSManagedObjectContext for you called *managedObjectContext. If you need to create other objects that are going to interact with your core data model (such as a view controller), you simply pass in that managedObjectContext object as an argument (or link it to a property in your custom class) and interact with it in your custom class. It's worth noting that it's not good practice to be passing around an AppDelegate object in your app. Your app delegate should be at the foundation of your code base and not treated as a typical class. There are definitely times when you will want (or need) to pass the app delegate as an object or reference it in IB, but typically your app will launch in your
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
method and you will launch your primary view controller from there.
Some things in core data also require the persistent store coordinator (such as retrieving managed object ID's), so you may need to pass that in as well. If you need some help working with Core Data, there are a bunch of great articles and books on the subject. I recommend reading as many as you can, since Core Data can be difficult to comprehend at first. It helped me to read a bunch of tutorials at first since everyone explains it a little differently.
Here's a great recent tutorial written on Bindings, Core Data, and working with the app delegate to get you started: http://www.raywenderlich.com/21752/how-to-use-cocoa-bindings-and-core-data-in-a-mac-app
In Cocos2d 2.0, AppDelegate is renamed to AppController
AppController *app = (AppController*)[UIApplication sharedApplication].delegate;
I have been making applications for Mac with Objective-C for about a year now but due to not really understanding how to use classes properly I have only ever used the 'AppDelegate' files. I want to start using classes as soon as possible because from what I understand it's very bad practice to clump it in to one class. Basically, how do I have two windows, each controlled by it's own class. I understand how to make objects similar to NSString or something but don't understand how to have classes that control windows etc.
Thanks
Edit: Basically I want to know how to split up my application in to classes.
If I understand you correctly then you need to create individual controller classes sporting their own IBOutlets and IBActions and hook these up to your UI elements. To split up an existing application into smaller classes requires some knowledge of Object Oriented programming.
Alternatively, you might benefit from reading this (or a similar) book:
'Cocoa Programming for Mac OS X' by Aaron Hillegass.
Try looking for NSWindowController in the docs. You create a custom subclass of NSWindowController and a xib file for it. In the xib file, make sure you set the class on the File's Owner to your custom subclass, and make sure its window outlet is connected to the window in the xib. If all that sounds totally foreign, head for the books! =)
Then, in the code where you want to bring this window onto the screen, you create an instance of your custom subclass and associate it with the xib, like so:
MyCustomWindowController *controller = [[MyCustomWindowController alloc] initWithWindowNibName:#"myxib"]
[controller showWindow:self];
The xib loading system will hook up all your custom outlets and actions on the new controller, and you can show it or do other wonderful NSWindowController things.
I'm a relatively new iOS developer, with most of my previous experience coming from .NET.
My application is a canvas like system in that there is a parent UIView that contains all the objects the user is placing/resizing/etc as subviews. I want to be able to save these positions/configurations to named files.
In .NET, I would have simply subclassed UIView, given it a "title" property, then serialized this to file, and then deserialized them to load them back, but in Cocoa I'm quite lost.
Originally I thought I could do this using NSCoding, but this doesn't seem to be a good solution for multiple file saving.
So I looked at Core Data, but I'm not sure how I can create Core Data objects of existing Cocoa UIKit classes like UIView.
I've spent a while googling and can't find any information about this kind of predicament.
What should I use, and what is the best way to go about it?
You probably could do it with NSKeyedArchiver, since UIView implements NSCoding. A more MVC-oriented design, however, would be to have the user manipulate a data model by moving the views around. To save, you'd archive the model rather than the views themselves.