Populating NSOutlineView with bindings - KVO adding of items - cocoa

I've created a small test project to play with NSOutlineView before using it in one of my projects. I'm successful in displaying a list of items with children using a NSTreeController who's content is bound to an Array.
Now while I created this object it took me ages to realize that my array contents would only show up if i created them in my init method:
- (id)init
{
self = [super init];
if (self) {
results = [NSMutableArray new];
NSMutableArray *collection = [[NSMutableArray alloc] init];
// Insert code here to initialize your application
NSMutableDictionary *aDict = [[NSMutableDictionary alloc] init];
[aDict setValue:#"Activities" forKey:#"name"];
NSMutableArray *anArray = [NSMutableArray new];
for (int i; i<=3 ; i++) {
NSMutableDictionary *dict = [NSMutableDictionary new];
[dict setValue:[NSString stringWithFormat:#"Activity %d", i] forKeyPath:#"name"];
[anArray addObject:dict];
}
results = collection;
}
return self;
}
If I put the same code in applicationDidFinishLaunching it wouldn't show the items.
I'm facing the same issue now when trying to add items to the view. My understanding of using the NSTreeController is that it handles the content similar to what NSArrayController does for a NSTableView (OutlineView being a subclass and all). However, whenever I use a KV compliant method to add items to the array the items do not show up in my view.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSMutableDictionary *cDict = [[NSMutableDictionary alloc] init];
[cDict setValue:#"Calls" forKey:#"name"];
[results addObject:cDict];
[outlineView reloadData];
}
I've also tried calling reloadData on the outlineview after adding an object, but that doesn't seem to be called. What am I missing?
Here's a link to my project: https://dl.dropboxusercontent.com/u/5057512/Outline.zip

After finding this answer:
Correct way to get rearrangeObjects sent to an NSTreeController after changes to nodes in the tree?
It turns out that NSTreeController reacts to performSelector:#selector(rearrangeObjects) withObject:afterDelay:
and calling this after adding the objects lets the new objects appear.

Related

Passing NSMutableArray with modal view

I have 2 views, in the second one I initialize a NSMutableArray and I want to pass it back to the first View. In the second view I have a button connected with the following action:
-(IBAction)back:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil]
}
With this action I go back from my second ViewController to the first ViewController, is there a way to pass the NSMutableArray from that action?
If you are not using prepareForSegue then you can user NSUserDefaults:
-(IBAction)back:(id)sender {
NSMutableArray *mutableArray = [[NSMutableArray alloc]init];
[[NSUserDefaults standardUserDefaults]setObject:mutableArray forKey:#"array"];
[self dismissViewControllerAnimated:YES completion:nil];
//I'm guessing you are going to load the viewController that's up next?
}
You can retrieve it in the viewDidLoad like so:
// to retrieve in maybe viewDidLoad?
NSArray * array = [[NSUserDefaults standardUserDefaults]arrayForKey:#"array"];
NSMutableArray *mutableArray = [array mutableCopy];

Nested NSCollection View

I am trying to create a nested collection view. First I did for one level.
Created a data model class with String header. In app delegate created an array sectionTitle. Now in the nib, I added collection view & array controller and did all the bindings following this guide. Next in awakeFromNib I populated some random data
- (void)awakeFromNib {
int idx = 0;
NSMutableArray *sectionTitle = [[NSMutableArray alloc] init];
while (idx < 1) {
HeaderModel *header = [[HeaderModel alloc] init];
[header setHeader:[NSString stringWithFormat:#"Section %d", idx]];
[sectionTitle addObject:header];
idx++;
}
[self setHeaderData:sectionTitle];
}
Running it will give me 4 sections. I want to achieve similar layout as this. Section title, under it another collection of items. The answer given there only hints at using Nested collection view.
So I added another collection view in the first view prototype. Then I followed the same approach what I did for the first view(with different data model and array).
- (void)awakeFromNib {
int idx = 0;
NSMutableArray *sectionTitle = [[NSMutableArray alloc] init];
NSMutableArray *groupData = [[NSMutableArray alloc] init];
while (idx < 1) {
HeaderModel *header = [[HeaderModel alloc] init];
DataModel *name = [[DataModel alloc] init];
[header setHeader:[NSString stringWithFormat:#"Section %d", idx]];
[name setName:[NSString stringWithFormat:#"Name %d", idx]];
[sectionTitle addObject:header];
[groupData addObject:name];
idx++;
}
[self setHeaderData:sectionTitle];
[self setData:groupData]; //NSCollectionView item prototype must not be nil.
}
But now I get the error NSCollectionView item prototype must not be nil.
How do I resolve this ?
I have just answered a similar question here
But somehow by inserting the second NSCollectionView with I.B, you get a corrupted prototype for your inner NSCollectionViewItem. Simply try to extract each associated NSView into its own .xib

NSCollectionView: Go to the next view on selection with Selected Item

I am new to OS X and have started dealing with NSCollectionView. What I am trying to do is to take show NSCollectionView with array of imageView an labels. And on the selection of the image I want to open a new viewController class. I am able to show array of images and labels in collection view but I am completely lost on how to go to new view with the selection made in NSCollectionView and how to show the image selected to the new viewController class.
I am having an NSTabView and in that I am having customView in which I am showing CollectionView. And in awakeFromNib I am doing this to populate my collectionView
-(void)awakeFromNib
{
arrItems = [[NSMutableArray alloc]init];
NSMutableArray *imageArray=[[NSMutableArray alloc]initWithObjects:#"Baby-Girl-Wallpaper-2012-7.jpg",#"Cute-Little-Baby-Girl.jpg",#"Joker_HD_Wallpaper_by_RiddleMeThisJoker.jpg",#"The-Dark-Angel-Wallpaper-HD.jpg",#"hd-wallpapers-1080p_hdwallpapersarena_dot_com.jpg",#"lion_hd_wallpaper.jpg",#"Ganesh_painting.jpg",#"krishna-wallpaper.jpg",#"LeoN_userpic_79630_fire_lion_by_alex_barrera.jpg",#"273483.png",#"japan_digital_nature-wide.jpg", nil];
NSMutableArray *imageName = [[NSMutableArray alloc]initWithObjects:#"Baby-Girl",#"Cute-Little",#"Joker",#"The-Dark",#"hd-wallpapers", #"lion", #"Ganesh", #"krishna", #"LeoN_userpic",#"273483.png",#"japan_digital", nil];
for(int i = 0; i<[imageArray count]; i++)
{
STImageCollectionModal * img1 = [[STImageCollectionModal alloc] init];
img1.image = [NSImage imageNamed:[imageArray objectAtIndex:i]];
img1.imageName = [NSString stringWithFormat:#"%#",[imageName objectAtIndex:i]];
[arrItems addObject:img1];
}
[collectionView setContent:arrItems];
}
Later I created a new class named "STCollectionView" subclass of NSCollectionView and assigned the collectionView class to "STCollectionView" and with the help of setSelectionIndexes method I tried getting the index of the selected item by this
- (void)setSelectionIndexes:(NSIndexSet *)indexes
NSLog(#"%ld",[indexes firstIndex]);
But this method is getting called twice and whenever i put "super setSelectionIndexes" it gives me garbage value.
I am searching it all over but unable to find any kind of solution. Please help..
Thank you in advance.
Your question is confusing me.What i am thinking you can do this task simply by adding UICollectionView and in UICollectionView add custom UICollectionViewCell.In custom UICollectionViewCell add UIImageView and UILabel.
in the method
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"ReuseID";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.imageView.image = [UIImage imagewithNmaed:#"your Image name"];
cell.label.text = #"image Named";
return cell;
}
and in storyBoard hold CLT+drag to your UIViewController.In the method prepareForSgue Method pass data to your Next viewController.

NSPopupButton in view based NSTableView: getting bindings to work

Problem Description
I'm trying to achieve something that should be simple and fairly common: having a bindings populated NSPopupButton inside bindings populated NSTableView. Apple describes this for a cell based table in the their documentation Implementing To-One Relationships Using Pop-Up Menus and it looks like this:
I can't get this to work for a view based table. The "Author" popup won't populate itself no matter what I do.
I have two array controllers, one for the items in the table (Items) and one for the authors (Authors), both associated with the respective entities in my core data model. I bind the NSManagedPopup in my cell as follows in interface builder:
Content -> Authors (Controller Key: arrangedObjects)
Content Values -> Authors (Controller Key: arrangedObjects, Model Key Path: name)
Selected Object -> Table Cell View (Model Key Path: objectValue.author
If I place the popup somewhere outside the table it works fine (except for the selection obviously), so I guess the binding setup should be ok.
Things I Have Already Tried
Someone suggested a workaround using an IBOutlet property to the Authors array controller but this doesn't seem to work for me either.
In another SO question it was suggested to subclass NSTableCellView and establish the required connections programmatically. I tried this but had only limited success.
If I setup the bindings as follows:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSView *view = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
if ([tableColumn.identifier isEqualToString:#"Author") {
AuthorSelectorCell *authorSelectorCell = (AuthorSelectorCell *)view;
[authorSelectorCell.popupButton bind:NSContentBinding toObject:self.authors withKeyPath:#"arrangedObjects" options:nil];
[authorSelectorCell.popupButton bind:NSContentValuesBinding toObject:self.authors withKeyPath:#"arrangedObjects.name" options:nil];
[authorSelectorCell.popupButton bind:NSSelectedObjectBinding toObject:view withKeyPath:#"objectValue.author" options:nil];
}
return view;
}
the popup does show the list of possible authors but the current selection always shows as "No Value". If I add
[authorSelectorCell.popupButton bind:NSSelectedValueBinding toObject:view withKeyPath:#"objectValue.author.name" options:nil];
the current selection is completely empty. The only way to make the current selection show up is by setting
[authorSelectorCell.popupButton bind:NSSelectedObjectBinding toObject:view withKeyPath:#"objectValue.author.name" options:nil];
which will break as soon as I select a different author since it will try to assign an NSString* to an Author* property.
Any Ideas?
I had the same problem. I've put a sample project showing this is possible on Github.
Someone suggested a workaround using an IBOutlet property to the Authors
array controller but this doesn't seem to work for me either.
This is the approach that did work for me, and that is demonstrated in the sample project. The missing bit of the puzzle is that that IBOutlet to the array controller needs to be in the class that provides the TableView's delegate.
Had the same problem and found this workaround - basically get your authors array controller out of nib with a IBOutlet and bind to it via file owner.
You can try this FOUR + 1 settings for NSPopUpbutton:
In my example, "allPersons" is equivalent to your "Authors".
I have allPersons available as a property (NSArray*) in File's owner.
Additionally, I bound the tableView delegate to File's owner. If this is not bound, I just get a default list :Item1, Item2, Item3
I always prefer the programmatic approach. Create a category on NSTableCellView:
+(instancetype)tableCellPopUpButton:(NSPopUpButton **)popUpButton
identifier:(NSString *)identifier
arrayController:(id)arrayController
relationship:(NSString *)relationshipName
relationshipArrayController:(NSArrayController *)relationshipArrayController
relationshipAttribute:(NSString *)relationshipAttribute
relationshipAttributeIsScalar:(BOOL)relationshipAttributeIsScalar
valueTransformers:(NSDictionary *)valueTransformers
{
NSTableCellView *newInstance = [[self alloc] init];
newInstance.identifier = identifier;
NSPopUpButton *aPopUpButton = [[NSPopUpButton alloc] init];
aPopUpButton.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[aPopUpButton bind:NSContentBinding //the collection of objects in the pop-up
toObject:relationshipArrayController
withKeyPath:#"arrangedObjects"
options:nil];
NSMutableDictionary *contentBindingOptions = [NSMutableDictionary dictionaryWithDictionary:[[TBBindingOptions class] contentBindingOptionsWithRelationshipName:relationshipName]];
NSValueTransformer *aTransformer = [valueTransformers objectForKey:NSValueTransformerNameBindingOption];
if (aTransformer) {
[contentBindingOptions setObject:aTransformer forKey:NSValueTransformerNameBindingOption];
}
[aPopUpButton bind:NSContentValuesBinding // the labels of the objects in the pop-up
toObject:relationshipArrayController
withKeyPath:[NSString stringWithFormat:#"arrangedObjects.%#", relationshipAttribute]
options:[self contentBindingOptionsWithRelationshipName:relationshipName]];
NSMutableDictionary *valueBindingOptions = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSAllowsEditingMultipleValuesSelectionBindingOption,
[NSNumber numberWithBool:YES], NSConditionallySetsEditableBindingOption,
[NSNumber numberWithBool:YES], NSCreatesSortDescriptorBindingOption,
[NSNumber numberWithBool:YES], NSRaisesForNotApplicableKeysBindingOption,
[NSNumber numberWithBool:YES], NSValidatesImmediatelyBindingOption,
nil];;
#try {
// The object that the pop-up should use as the selected item
if (relationshipAttributeIsScalar) {
[aPopUpButton bind:NSSelectedValueBinding
toObject:newInstance
withKeyPath:[NSString stringWithFormat:#"objectValue.%#", relationshipName]
options:valueBindingOptions];
} else {
[aPopUpButton bind:NSSelectedObjectBinding
toObject:newInstance
withKeyPath:[NSString stringWithFormat:#"objectValue.%#", relationshipName]
options:valueBindingOptions];
}
}
#catch (NSException *exception) {
//NSLog(#"%# %# %#", [self class], NSStringFromSelector(_cmd), exception);
}
#finally {
[newInstance addSubview:aPopUpButton];
if (popUpButton != NULL) *popUpButton = aPopUpButton;
}
return newInstance;
}
+ (NSDictionary *)contentBindingOptionsWithRelationshipName:(NSString *)relationshipNameOrEmptyString
{
NSString *nullPlaceholder;
if([relationshipNameOrEmptyString isEqualToString:#""])
nullPlaceholder = NSLocalizedString(#"(No value)", nil);
else {
NSString *formattedPlaceholder = [NSString stringWithFormat:#"(No %#)", relationshipNameOrEmptyString];
nullPlaceholder = NSLocalizedString(formattedPlaceholder,
nil);
}
return [NSDictionary dictionaryWithObjectsAndKeys:
nullPlaceholder, NSNullPlaceholderBindingOption,
[NSNumber numberWithBool:YES], NSInsertsNullPlaceholderBindingOption,
[NSNumber numberWithBool:YES], NSRaisesForNotApplicableKeysBindingOption,
nil];
}

initWithDictionary

I have the problem that I can't get the Data from one of my classes to the other...
To do this I created this method in the class I am initializing (angebotPage):
- (id) initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self) {
dict = [dictionary retain];
}
return self;
}
The call from the other class looks like this:
angebotPage *page;
angebotPDF = [[PDFDocument alloc] init];
page = [[angebotPage alloc] initWithDictionary:dictionary];
The Error I get is EXC_BAD_ACCESS in the line where I do:
dict = [dictionary retain];
But why? I need to retain it cause I will use it for the next program steps.. But without retaining I can't use it (EXC_BAD_ACCESS comes elsewhere...)
I recommend that you use a property for dict instead.
#property (retain) NSDictionary *dict;
And then assign the dictionary with self.dict = dictionary. This is assuming all the objects in dictionary are correctly retained in the first place. Try with an empty dictionary if in doubt.

Resources