How to prevent retain cycles caused by binding to self - cocoa

I have an application where I need to access model data from my subviews. I've been using bindings to pass data across views; however, the bindings to self seem to be causing retain cycles (dealloc never gets called). When should I remove the bindings if not in the dealloc method? Thanks.
P.S. I know the method of binding to a proxy object controller, but I'd like to avoid using it if possible.
Here's an example of what I've been doing:
// Top-level Project view
#interface ProjectViewController : NSViewController {
FoldersView *foldersView;
}
#property (strong) NSObjectController *projectObjectController; // holds Project instance
end
// Displays folders
#interface FoldersView : NSView {
FolderView *folderView;
}
#property (weak) NSObjectController *projectObjectController; // binded from parent
#property (strong) NSArrayController *foldersArrayController; // binded to project.folders
#end
// Displays selected folder
#interface FolderView : NSView
#property (weak) NSArrayController *foldersArrayController; // binded from parent
#property (strong) NSObjectController *folderObjectController; // binded to folders.selection
#end

The bindings are the preferred way of removing C part (boilerplate code) from the MVC trinity. So your approach to handling this problem is correct.

Related

NSCollectionViewItem with a custom view

I've been struggling with trying to create an NSCollectionView that has a set of NSCollectionViewItems with a custom view. The code works fine when the controls on the item view are standard AppKit controls, but once I add a custom NSView, there's no way to bind it from Interface Builder.
From spending some hours searching the internet, there appears to be a lot of options to solve this but all seem specialised. Is there some simple example code that demonstrates how, given a CustomImage * on the item view, to set the image property on that custom view?
The model that provides data for each item is:
#interface MyItem : NSObject
#property (retain, readwrite) NSImage * image;
#property (retain, readwrite) NSString * name;
#end
The NSCollectionViewItem subclass is:
#interface MyCollectionViewItem : NSCollectionViewItem
// Properties
#property (strong) IBOutlet NSTextField * name;
#property (strong) IBOutlet CustomImage * image;
#end
where CustomImage is simply a subclass of NSImageView.
I tried subclassing NSCollectionView and overriding newItemForRepresentedObject as some answers suggested and assigning there:
MyItem * item = (MyItem *)object;
MyCollectionViewItem * newItem = (MyCollectionViewItem *)[super newItemForRepresentedObject:object];
NSView *view = [newItem view];
[view bind:#"name" toObject:item withKeyPath:#"name" options:nil];
[view bind:#"image" toObject:item withKeyPath:#"image" options:nil];
return newItem;
but this just blew up in the bind call with an error that 'name' doesn't exist.
This should, in theory, be an extremely simple thing to solve but none of the answers I've found make this clear. An alternative would be to ditch NSCollectionView and use one of the simpler replacements on GitHub but I'd like to have a last attempt to see if this is solvable first.
Thanks!
How did you add the CustomImage instance to the item view?
If you drag a "Custom View" in and then change the class, IB doesn't treat it like an NSImageView.
However, if you drag out an NSImageView and then change the class, IB should still treat it like an NSImageView and you should be able to bind its bindings like normal. In that case, you can bind its Value binding to the collection view item, model key path "representedObject.image".

NSArrayController, NSPopupButton proper bindings

I just started Mac programming coming over from iOS and was playing around with bindings.
I'm trying to make a simple directory popup that shows a history of recently selected directories and last element would read other... which will open the opendialog box.
I can't seem to figure out how to Bind an NSPopupButton to my Model though.
Its setup like this:
MainUIViewController, NSController, NSObject Controller all wired up in the nib
I do connect an outlet in MainUIViewController to the Directory Array Controller in the NIB
I have a class for eachDirectory, and a class for DirectoryArrayController(NSObject) I bind the NSPopupButton on view this way:
and I have the Directory Array Controller bound to the Directory Popup Array Controller thus
Here is the .h file that is connected to the Directory Popup Array Controller
#interface DirectoryPopupArrayController : NSObject
#property (weak) IBOutlet NSPopUpButton *directoryPopupButton;
#property (nonatomic) IBOutlet NSMutableArray *allDirectoryHistory;
#property (nonatomic) eachDirectory *currentlySelectedDirectory;
#end
I fill some sample directory info with the following code in the corresponding .m file
- (void)awakeFromNib {
[super awakeFromNib];
//testing sample directories
self.allDirectoryHistory = [[NSMutableArray alloc] initWithCapacity:10];
NSString *name;
eachDirectory *newDirectoryName;
for (int i = 0; i < 5; i++) {
name = [NSString stringWithFormat:#"directory %d", i];
newDirectoryName = [[eachDirectory alloc] initWithDirectoryName:name];
[self.allDirectoryHistory addObject:newDirectoryName];
}
}
and here is the code for the eachDirectory.h
#interface eachDirectory : NSObject
#property (nonatomic) NSString *directoryPath;
#property (nonatomic) NSString *directoryVisibleName;
-(id) initWithDirectoryName:(NSString *)newName;
#end
Now When I go to my code if I place the code for creation of the Array and bind the Array controller directly to the UIViewController.m file things seem to work fine.
What I want to do is handle all the array stuff in a separate class file and only get back the final directory choice to the main controller. When I bind the NSArrayController to the Object controller in the NIB as described above I get nothing showing in the popup and I don't understand why!
Any Help is greatly appreciated, Sorry for the long-winded post - just wanted to make myself clear.

Set view as delegate to viewcontroller

I'm having problem passing data and executing functions in the viewcontroller from the view. I want to access label outlets in the viewcontroller from the view (yeah I know it might be bad structure of my app).
Got delegations working on UIPopovers but how can I set the delegate of the view to viewcontroller?
For example, you have a subclass of UIView. Let's name it SubClassUIView;
In another view, you want to use the data, from SubClassUIView.
So, your SubClassUIView should be done like this:
SubClassUIView.h
#interface SubClassUIView:UIView
#property (nonatomic, retain) UILabel* someLabelYouWantToUse;
#end.
SubClassUIView.m
#implementation SubClassUIView
#synthesize someLabelYouWantToUse;
#end.
And to access someLabelYouWantToUse
SubClassUIView* scView = [SubClassUIView alloc]init];
NSLog(#"%#", scView.someLabelYouWantToUse.text);

NSController with own xib file but no view

I'm creating a MenuBar-Application with a couple of popup-windows, a NSMenu and some regular windows for settings and stuff like that.
I created a NSController to hold all my StatusBar stuff together and notify the popup to open and close.
The popup has it's own PopupWindowController and xib file wich works like a charm. But i can't get it to work with the NSMenu (in my case it's subclassed as RightClickMenu)
In IB i created an other .xib called StatusBarController.xib (with StatusBarController as the file's owner) with the menu and linked it to the outlet.
...
#class RightClickMenu;
#interface StatusBarController : NSController <NSMenuDelegate> {
IBOutlet RightClickMenu *rightClickMenu;
}
#property (nonatomic, retain) RightClickMenu *rightClickMenu;
...
My AppDelegate has a IBOutlet StatusBarController property and a the main .xib which is linked to the NScontroller object.
#class StatusBarController;
#interface MyAppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet StatusBarController *statusBarController;
...
Hope you can help...
cheers
your variable! is an outlet but your property is not
IB uses KVC to set outlets and that will find your property which will use _variable
BTW just in case:
you gotta handle the loading yourself EXCEPT if you subclass NSViewController
in init of the controller you do a [[NSBundle mainBundle] loadNibName:#"bla" owner:self];

Cocoa Bindings: NSObjectController not KVC-compliant for the representedObject property

I've been through a bunch of Core Data examples and the Apple documentation. I'm at a wall after working on this all day.
All I want to happen is I type some text into a text field, save the file, open it again and see the text there.
I made a very very simple Core Data document-based app to experiment. Here are the particulars:
1) The data model has one Entity ("Note") with one attribute ("title") which is an NSString.
2) I created a view controller "ManagingViewController" that loads in a view called "NoteView" into a box in MyDocument.xib without a problem. NoteView.nib has just one NSTextField in it.
ManagingViewController.h
#import <Cocoa/Cocoa.h>
#import "Note.h"
#interface ManagingViewController : NSViewController {
NSManagedObjectContext *managedObjectContext;
IBOutlet NSTextField *title;
}
#property (retain) NSManagedObjectContext *managedObjectContext;
#property (retain, readwrite) NSTextField *title;
#end
and ManagingViewController.m
#import "ManagingViewController.h"
#import "Note.h"
#implementation ManagingViewController
#synthesize managedObjectContext;
#synthesize title;
- (id)init
{
if (![super initWithNibName:#"NoteView" bundle:nil]) {
return nil;
}
return self;
}
#end
I have a NSManagedObject called "Note.h"
#import <CoreData/CoreData.h>
#import "ManagingViewController.h"
#interface Note : NSManagedObject
{
}
#property (nonatomic, retain) NSString * title;
#end
and the .m file:
#import "Note.h"
#import "ManagingViewController.h"
#implementation Note
#dynamic title;
#end
In NoteView.nib my:
1) File's Owner is ManagingViewController and the IBOutlets to the Text Field and the view are connected.
2) I dragged over an NSObjectController object into the Interface Builder document window called "Note Object Controller". I set mode to "Entity" and the Entity Name to "Note". "Prepares content" and "Editable" are checked on. (All the examples I've done and been able to find use an NSArrayController here. I don't need an array controller right? I do want to be able to open multiple windows for the same app but I still don't think I need an arraycontroller? All the examples have a NSTableView and a add button. There's no need for an add button here since I don't have an NSTableView).
3) The NSTextView bindings for value I have it bound to "Note Object Controller" with a controller key of representedObject and a Model Key Path of title.
When I run my app I get
[<NSObjectController 0x20004c200> addObserver:<NSTextValueBinder 0x20009eee0>
forKeyPath:#"representedObject.title" options:0x0 context:0x20009f380] was
sent to an object that is not KVC-compliant for the "representedObject" property.
What am I doing wrong? I want to type in the text field, save the file, open it again and see the text there.
[<NSObjectController 0x20004c200> addObserver:<NSTextValueBinder 0x20009eee0> forKeyPath:#"representedObject.title" options:0x0 context:0x20009f380] was sent to an object that is not KVC-compliant for the "representedObject" property.
What am I doing wrong?
The error message tells you what you're doing wrong: You're trying to bind to the representedObject property of your object controller, but it doesn't have one. Binding to properties that don't exist cannot work.
The Note is the content object of the NSObjectController, so that's the controller key you need to bind to: content.

Resources