setting Array in model-class from NSArrayController - macos

How do I set the array in my model-class ValueItem with the content of an NSArrayControllerin my AppDelegate class:
#interface AppDelegate : NSObject <NSApplicationDelegate>
{
ValueItem *vi;
}
and:
#implementation AppDelegate
{
ValueItem *array = [[ValueItem alloc]init];
[array setValueArray:[outArrayController arrangedObjects]];
NSArray *testArray2 = vi.valueArray; // !!!getter or setter doesn't work!!!
NSLog(#"test array 2 is:%#", testArray2);
}
NSLog returns NULL. What do I miss here?
(valueArray is initialized with #property and #synthesize)
ValueItem.h:
#import <Foundation/Foundation.h>
#interface ValueItem : NSObject
{
NSNumber *nomValue;
NSNumber *tolerancePlus;
NSNumber *toleranceMinus;
NSMutableArray *valueArray;
}
#property (readwrite, copy) NSNumber *nomValue;
#property (readwrite, copy) NSNumber *tolerancePlus;
#property (readwrite, copy) NSNumber *toleranceMinus;
#property (nonatomic, retain) NSMutableArray *valueArray;
#end
ValueItem.m:
#import "ValueItem.h"
#implementation ValueItem
#synthesize nomValue, tolerancePlus, toleranceMinus;
#synthesize valueArray;
-(NSString*)description
{
return [NSString stringWithFormat:#"nomValue is: %# | tolerancePlus is: %# | toleranceMinus is: %#", nomValue, tolerancePlus, toleranceMinus];
}
#end

Solution: Need to make sure you're dealing with the AppDelegate's vi property:
// We need to make sure we're manipulating the AppDelegate's vi property!
self.vi = [[ValueItem alloc]init];
[vi setValueArray:[outArrayController arrangedObjects]];
NSArray *testArray2 = vi.valueArray; // !!!getter or setter doesn't work!!!
NSLog(#"test array 2 is:%#", testArray2);
Explanation :
On the first two lines you were manipulating the array ValueItem variable, then attempting to set testArray2 to the value of the uninitialized vi ValueItem variable.
// This is a new variable, unrelated to AppDelegate.vi
ValueItem *array = [[ValueItem alloc]init];
[array setValueArray:[outArrayController arrangedObjects]];
// Here, AppDelegate.vi hasn't been initialized, so valueArray *will* be null!
NSArray *testArray2 = vi.valueArray;
NSLog(#"test array 2 is:%#", testArray2);

Related

Adding objects to array NSXMlParser no data

I'm trying to make a XML-parser that saves data from YR.no-API. The parser should add data to these two datastructures. My problem is when i try to add a WeatherTimeData object to my array in WeatherData, it seems like the objects doesnt get added, the following count always give me zero
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"time"])
{
[self.weatherdata.timedata addObject:currentWeatherTimeData];
NSLog(#"amount of objects in timedata-array %d", [[self.weatherdata timedata] count]);
}
These are my two data-structures, i alloc weatherData in the following method
-(id) loadXMLByURL:(NSString *)urlString
{
_weatherdata = [[WeatherData alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
Do i have to alloc the array inside of the weatherdata object?
WeatherData.h
#interface WeatherData : NSObject
#property (strong, nonatomic)NSString *town;
#property (strong, nonatomic)NSString *country;
#property (strong, nonatomic)NSMutableArray *timedata;
#end
WeatherData.m
#implementation WeatherData
#synthesize town = _town;
#synthesize country = _country;
#synthesize timedata = _timedata;
#end
WeatherTimeData.h
#interface WeatherTimeData : NSObject
#property (strong, nonatomic)NSDate *startTime;
#property (strong, nonatomic)NSDate *endTime;
#property (strong, nonatomic)NSString *iconSymbol;
#property (strong, nonatomic)NSString *windDirection;
#property (strong, nonatomic)NSString *windSpeed;
#property (strong, nonatomic)NSString *temprature;
#property (strong, nonatomic)NSString *preassure;
#end
WeatherTimeData.m
#implementation WeatherTimeData
#synthesize startTime = _startTime;
#synthesize endTime = _endTime;
#synthesize iconSymbol = _iconSymbol;
#synthesize windDirection = _windDirection;
#synthesize windSpeed = _windSPeed;
#synthesize temprature = _temprature;
#synthesize preassure = _preassure;
#end
This type of problem is classically because the object hasn't been allocated, and given Objective-C allows messages to be sent to nil the programmer doesn't notice.
I think it would be nice to be able to provide a runtime environment variable where such events are logged to stdout...
I would suspect that [WeatherTimeData init] isn't creating timedata and that's because you haven't provided an implementation for it; just using #sythensize isn't enough to create the objects.

How are dependent keys registered? (Key-Value Observing)

I have created a simple Cocoa Application. In MainMenu.xib I have added an NSDatePicker and an NSTextField. Both of these objects have Value bindings to properties of the App Delegate. I expect that when the user changes the date in the NSDatePicker, the NSTextField will be updated. This isn't happening. Here is the App Delegate:
// AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#property (nonatomic, strong) NSDate *dateFromPicker;
#property (nonatomic, readonly) NSString *dateString;
#end
// AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
}
- (NSString *)dateString
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
return [formatter stringFromDate:self.dateFromPicker];
}
+ (NSSet *)keyPathsForValuesAffectingDateString
{
return [NSSet setWithObject:#"dateFromPicker"];
}
#end
Updated code with an observer for dateFromPicker and some NSLog statements:
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[self addObserver:self forKeyPath:#"dateFromPicker" options:0 context:NULL];
self.dateFromPicker = [NSDate dateWithNaturalLanguageString:#"12/12/12"];
}
- (NSString *)dateString
{
NSLog(#"dateString was called.");
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
return [formatter stringFromDate:self.dateFromPicker];
}
+ (NSSet *)keyPathsForValuesAffectingDateString
{
NSLog(#"keyPathsForValuesAffectingDateString was called.");
return [NSSet setWithObject:#"dateFromPicker"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change: (NSDictionary *)change context:(void *)context
{
NSLog(#"dateFromPicker changed.");
}
#end
Here is the log:
2012-08-10 15:37:15.086 ... keyPathsForValuesAffectingDateString was called.
2012-08-10 15:37:15.087 ... dateString was called.
2012-08-10 15:37:15.116 ... dateFromPicker changed.
2012-08-10 15:37:15.117 ... dateString was called.
2012-08-10 15:37:19.831 ... dateFromPicker changed.
2012-08-10 15:37:19.831 ... dateString was called.
I know this is not exactly what you were asking, but ...
Why don't you bind the NSTextField to the NSDate property and add a formatter to it in Interface Builder?

how to set the property of the ViewController before presenting it as presentModalViewController?

I present the view controller like this:
FBViewController *fbViewController =[[FBViewController alloc] initWithNibName:#"FBViewController" bundle:nil];
fbViewController.label.text=#"hello"; // I set the value of the property label which is the outlet
[self presentModalViewController:fbViewController animated:YES];
FBViewController.h:
#import <UIKit/UIKit.h>
#interface FBViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#end
FBViewController.m:
...
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", self.label.text); // Here instead of "hello" i get the value which was in nib file.
}
...
The question is how to set the value of the label?
You can pass the NSString retrieve text to assign label modalview controller:
FBViewController *fbViewController =[[FBViewController alloc] initWithNibName:#"FBViewController" bundle:nil];
fbViewController.labeltext=#"Your Text";
[self presentModalViewController:fbViewController animated:YES];
FBViewController.h
#interface FBViewController : UIViewController {
NSString *labeltext;
}
#property (nonatomic, retain) NSString *labeltext;
and use view to load method in FBViewController.m
- (void)viewDidLoad {
label1.text=labeltext;
}

Accessing NSTextField from its delegate notification…

I'm subclassing NSTextField
MultiTextField.h
#import <AppKit/AppKit.h>
#interface MultiTextField : NSTextField {
id storedObject;
}
#property (nonatomic, retain) id storedObject;
#end
MultiTextField.m
#import "MultiTextField.h"
#implementation MultiTextField
#synthesize storedObject;
#end
to store a pointer to an object, which I want to "rename".
I made this textfield editable and have a delegate which listens to controlTextDidChange: and works fine:
- (void)controlTextDidChange:(NSNotification *)aNotification {
NSTextView *textView = [[aNotification userInfo] objectForKey:#"NSFieldEditor"];
NSString *theString = [[textView textStorage] string];
if([theString length] > 0 ) {
MyObject *theObject = ???; // I need access to the MultiTextField.storedObject!
[theObject setName:theString];
}
}
the only problem is that I can't access the storedObject (see comment in the if-block).
So how do I access that storedObject?
Try this:
MyObject *theObject = [[aNotification object] storedObject];

Cocoa class not displaying data in NSWindow

I have one class that controls one window, and another class that controls a different window in the same xib, however, the second window never displays what it should.
In the first class I alloc and init the second class, then pass some information to it. In the second class it displays that data in the table view.
Yes, in the .xib I have all the connections set up correctly, I've quadruple checked. Also the code is correct, same with the connections, I've quadruple checked.
Edit: and yes, there's data in the arrays, and the classes are NSObjects.
Edit2: I kinda found the problem. For some reason, the array is filled with contents, but it's returning 0 as a count.
Edit 9000:
Here's the code:
Answer.h
#import <Cocoa/Cocoa.h>
#interface MSAnswerView : NSObject {
IBOutlet NSWindow *window;
NSArray *User;
NSArray *Vote;
NSArray *Text;
IBOutlet NSTableView *view;
IBOutlet NSTableColumn *voteCount;
IBOutlet NSTableColumn *saidUser;
IBOutlet NSTextView *body;
}
-(void)setUpWithVoteCount:(NSArray *)array User:(NSArray *)user Text:(NSArray *)text;
#property (nonatomic, retain) NSWindow *window;
#property (nonatomic, retain) NSTableView *view;
#property (nonatomic, retain) NSTableColumn *voteCount;
#property (nonatomic, retain) NSTableColumn *saidUser;
#property (nonatomic, retain) NSTextView *body;
#end
.m
#import "MSAnswerView.h"
#implementation MSAnswerView
#synthesize view;
#synthesize voteCount;
#synthesize saidUser;
#synthesize body;
#synthesize window;
-(void)awakeFromNib
{
[view setTarget:self];
[view setDoubleAction:#selector(bodydata)];
[view reloadData];
}
-(void)setUpWithVoteCount:(NSArray *)array User:(NSArray *)user Text:(NSArray *)text
{
Vote = array;
User = user;
Text = text;
if (window.isVisible = YES) {
[view reloadData];
[view setNeedsDisplay];
}
}
-(int)numberOfRowsInTableView:(NSTableView *)aTable
{
return [User count];;
}
-(id)tableView:(NSTableView *)aTable objectValueForTableColumn:(NSTableColumn *)aCol row:(int)aRow
{
if (aCol == voteCount)
{
return [Vote objectAtIndex:aRow];
}
else if (aCol == saidUser)
{
return [User objectAtIndex:aRow];
}
else
{
return nil;
}
}
-(void)bodydata
{
int index = [view selectedRow];
[body setString:[Text objectAtIndex:index]];
}
#end
The problems in your code are numerous.
For one thing, this comparison in -setUpWithVoteCount:User:Text: is incorrect:
window.isVisible = YES
That should be the comparison operator, == not the assignment operator =.
Secondly, you are naming your ivars and methods incorrectly. Instance variables (in fact, variables of any type) should start with a lower-case letter. This is to distinguish them from class names. Check out the Apple coding guidelines.
I'd also suggest that a name like text is a bad name for a variable that stores a collection like an NSArray. Instead, you should name it something like textItems so it's clear that the variable represents a collection and not a single string.
Also, the class itself is poorly named. You have called it MSAnswerView but it's not a view, it's some type of window controller. At the very least call it MSAnswerWindowController. Better still would be to make it a subclass of NSWindowController and make it File's Owner in its own nib. This is the standard pattern for window controllers.
Your method -setUpWithVoteCount:User:Text: should really be an initializer:
- initWithVoteCount:user:text:
That way it's clear what it's for and that it should be called once at object creation time.
The main problem, however, is that you're not retaining the values that you pass in to your setup method. That means that if no other object retains a reference to them, they will go away at some indeterminate point in the future. If you access them at a later time, you will crash or at the very least receive bad data, which is what's occurring.
Of course, you must also add a -dealloc method in this case to ensure you release the objects when you're finished with them.
Putting all those suggestions together, your class should really look something like this:
MSAnswerWindowController.h:
#import <Cocoa/Cocoa.h>
//subclass of NSWindowController
#interface MSAnswerWindowController : NSWindowController <NSTableViewDataSource>
{
//renamed ivars
NSArray *users;
NSArray *voteCounts;
NSArray *textItems;
IBOutlet NSTableView *view;
IBOutlet NSTableColumn *voteCount;
IBOutlet NSTableColumn *saidUser;
IBOutlet NSTextView *body;
}
//this is now an init method
- (id)initWithVoteCounts:(NSArray *)someVoteCounts users:(NSArray *)someUsers textItems:(NSArray *)items;
//accessors for the ivars
#property (nonatomic, copy) NSArray* users;
#property (nonatomic, copy) NSArray* voteCounts;
#property (nonatomic, copy) NSArray* textItems;
#property (nonatomic, retain) NSWindow *window;
#property (nonatomic, retain) NSTableView *view;
#property (nonatomic, retain) NSTableColumn *voteCount;
#property (nonatomic, retain) NSTableColumn *saidUser;
#property (nonatomic, retain) NSTextView *body;
#end
MSAnswerWindowController.m:
#import "MSAnswerWindowController.h"
#implementation MSAnswerWindowController
//implement the init method
- (id)initWithVoteCounts:(NSArray*)someVoteCounts users:(NSArray*)someUsers textItems:(NSArray*)items
{
//this is an NSWindowController, so tell super to load the nib
self = [super initWithWindowNibName:#"MSAnswerWindow"];
if(self)
{
//copy all the arrays that are passed in
//this means we hold a strong reference to them
users = [someUsers copy];
voteCounts = [someVoteCounts copy];
textItems = [items copy];
}
return self;
}
//make sure we deallocate the object when done
- (void)dealloc
{
self.users = nil;
self.voteCounts = nil;
self.textItems = nil;
[super dealloc];
}
//this is called when the window first loads
//we do initial window setup here
- (void)windowDidLoad
{
[view setTarget:self];
[view setDataSource:self];
[view setDoubleAction:#selector(bodydata)];
}
//this is called when the view controller is asked to show its window
//we load the table here
- (IBAction)showWindow:(id)sender
{
[super showWindow:sender];
[view reloadData];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView*)aTable
{
return [users count];
}
- (id)tableView:(NSTableView*)aTable objectValueForTableColumn:(NSTableColumn*)aCol row:(NSInteger)aRow
{
if (aCol == voteCount)
{
return [voteCounts objectAtIndex:aRow];
}
else if (aCol == saidUser)
{
return [users objectAtIndex:aRow];
}
return nil;
}
- (void)bodydata
{
NSInteger index = [view selectedRow];
[body setString:[textItems objectAtIndex:index]];
}
#synthesize users;
#synthesize voteCounts;
#synthesize textItems;
#synthesize view;
#synthesize voteCount;
#synthesize saidUser;
#synthesize body;
#end

Resources