I'm writing an OSX app where a second window is opened to show results when the button on the first window is pushed. The window-2 start fine and shows what I want. But when I change inputs in window-1 and hit the action button again the window-2 doesn't update the results.
here my questions:
how does the content of window-2 update after input change in window-1
how is window-2 closed and released (right now window-2 shows up with the same content before closed when action button is pushed again)
here is the code for the action button:
- (IBAction)pushRun:(id)sender {
if (!rwc)
{
rwc = [[ResultWindowController alloc] init];
[rwc setValueArray:[toDoItemArrayController arrangedObjects]];
[rwc setNumberOfCalculations:[NSNumber numberWithInt:[_inputNumberOfCalculations intValue]]];
[rwc calculateResults]; //starts method in 2nd-window controller for result calculation
}
[rwc showWindow:self];
}
It might be easy but I'm afraid to always create an other ResultWindowController instance.
Thanks in advance.
Joerg
here is the ResultWindowController.h:
#import <Cocoa/Cocoa.h>
#interface ResultWindowController : NSWindowController{
NSArray *valueArray;
NSMutableArray *resultArray;
NSNumber *numberOfCalculations;
}
#property (nonatomic, retain, readwrite) NSArray *valueArray;
#property (retain) NSNumber *numberOfCalculations;
#property (nonatomic, retain, readwrite) NSMutableArray *resultArray;
-(void)calculateResults;
#end
and here the ResultWindowController.m
#import "ResultWindowController.h"
#import "ResultItem.h" //my result model
#implementation ResultWindowController
#synthesize valueArray, resultArray, numberOfCalculations;
- (id)init
{
if(![super initWithWindowNibName:#"ResultWindow"])
return nil;
return self;
}
-(void)awakeFromNib
{
}
- (void)windowDidLoad
{
[super windowDidLoad];
}
- (void)calculateResults
{
//a lot of calculation code ...
ResultItem *newResult = [[ResultItem alloc]init];
[newResult setValue:[nameArray objectAtIndex:i] forKey:#"name"];
[newResult setValue:[NSNumber numberWithDouble:avg] forKey:#"averageValue"];
[newResult setValue:[NSNumber numberWithDouble:min] forKey:#"minValue"];
[newResult setValue:[NSNumber numberWithDouble:max] forKey:#"maxValue"];
[newResult setValue:dimensionRandomArray forKey:#"randomArray"];
[resultArray addObject:newResult];
}
resultarray is the content source for an arraycontroller in the ResultWindowController.xib. The arraycontroller is bound to a table view which is supposed to show the array content. This is not updated the second time.
I believe you must simply do the following:
- (IBAction)pushRun:(id)sender {
if (!rwc)
{
rwc = [[ResultWindowController alloc] init];
[rwc setValueArray:[toDoItemArrayController arrangedObjects]];
[rwc setNumberOfCalculations:[NSNumber numberWithInt:[_inputNumberOfCalculations intValue]]];
[rwc calculateResults]; //starts method in 2nd-window controller for result calculation
}
[rwc setValueArray:[toDoItemArrayController arrangedObjects]];
[rwc setNumberOfCalculations:[NSNumber numberWithInt:[_inputNumberOfCalculations intValue]]];
[rwc calculateResults]; //starts method in 2nd-window controller for result
[rwc showWindow:self];
}
You were only changing values of ResultWindowController if it did not exist. You want to change values no matter what, just not start a new instance. So, as long as you don't use [[alloc]init] you're good.
Hope that helps. If you need anything else, drop a comment.
Edit
To create a property for your tableView do the following:
In .h
#import <Cocoa/Cocoa.h>
#interface ResultWindowController : NSWindowController{
NSArray *valueArray;
NSMutableArray *resultArray;
NSNumber *numberOfCalculations;
}
#property (nonatomic, retain, readwrite) NSArray *valueArray;
#property (retain) NSNumber *numberOfCalculations;
#property (nonatomic, retain, readwrite) NSMutableArray *resultArray;
#property (assign) NSTableView *yourTableView; //Add this code
-(void)calculateResults;
#end
and here the ResultWindowController.m
#import "ResultWindowController.h"
#import "ResultItem.h" //Your result model
#implementation ResultWindowController
#synthesize valueArray, resultArray, numberOfCalculations;
#synthesize yourTableView; //Add this code
Then you should be able to call [yourTableView reloadData]
Related
I know theres a better solution using arc4random (it's on my to-try-out-function list), but I wanted to try out using the rand() and stand(time(NULL)) function first. I've created a NSMutableArray and chuck it with 5 data. Testing out how many number it has was fine. But when I tried to use the button function to load the object it return me with object <sampleData: 0x9a2f0e0>
- (IBAction)generateNumber:(id)sender {
srand(time(NULL));
NSInteger number =rand()% ds.count ;
label.text = [NSString stringWithFormat:#"object %#", [ds objectAtIndex:number] ];
NSLog(#"%#",label.text);
}
While I feel the main cause is the method itself, I've paste the rest of the code below just incase i made any error somewhere.
ViewController.h
#import <UIKit/UIKit.h>
#import "sampleData.h"
#import "sampleDataDAO.h"
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet UIButton *onHitMePressed;
- (IBAction)generateNumber:(id)sender;
#property(nonatomic, strong) sampleDataDAO *daoDS;
#property(nonatomic, strong) NSMutableArray *ds;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize label;
#synthesize onHitMePressed;
#synthesize daoDS,ds;
- (void)viewDidLoad
{
[super viewDidLoad];
daoDS = [[sampleDataDAO alloc] init];
self.ds = daoDS.PopulateDataSource;
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setLabel:nil];
[self setOnHitMePressed:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (IBAction)generateNumber:(id)sender {
srand(time(NULL));
NSInteger number =rand()% ds.count ;
label.text = [NSString stringWithFormat:#"object %#", [ds objectAtIndex:number] ];
NSLog(#"%#",label.text);
}
#end
sampleData.h
#import <Foundation/Foundation.h>
#interface sampleData : NSObject
#property (strong,nonatomic) NSString * object;
#end
sampleData.m
#import "sampleData.h"
#implementation sampleData
#synthesize object;
#end
sampleDataDAO.h
#import <Foundation/Foundation.h>
#import "sampleData.h"
#interface sampleDataDAO : NSObject
#property(strong,nonatomic)NSMutableArray*someDataArray;
-(NSMutableArray *)PopulateDataSource;
#end
sampleDataDAO.m
#import "sampleDataDAO.h"
#implementation sampleDataDAO
#synthesize someDataArray;
-(NSMutableArray *)PopulateDataSource
{
someDataArray = [[NSMutableArray alloc]init];
sampleData * myData = [[sampleData alloc]init];
myData.object= #"object 1";
[someDataArray addObject:myData];
myData=nil;
myData = [[sampleData alloc] init];
myData.object= #"object 2";
[someDataArray addObject:myData];
myData=nil;
myData = [[sampleData alloc] init];
myData.object= #"object 3";
[someDataArray addObject:myData];
myData=nil;
myData = [[sampleData alloc] init];
myData.object= #"object 4";
[someDataArray addObject:myData];
myData=nil;
myData = [[sampleData alloc] init];
myData.object= #"object 5";
[someDataArray addObject:myData];
myData=nil;
return someDataArray;
}
#end
what i guess is going on is that nslog function cant print the data inside your sample data class because its not a standard class. not standard classes must implement the "description" method. What you get when you print out your class is the pointer to it, because nslog has no way of knowing how to print out the data in your class.
if what you want to print on that label/nslog is the nsstring inside your class "sampledata" you should access the property.
this can be done in the following way:
SampleData *instanceOfSampleData = (SampleData*)[ds objectAtIndex:number];
label.text = [NSString stringWithFormat:#"object %#", instanceOfSampleData.object];
So I'm creating an array called fruits which I would like to share between multiple views. This is my code:
#import <foundation/Foundation.h>
#interface MyManager : NSObject {
NSMutableArray *fruits;
}
#property (nonatomic, retain) NSMutableArray *fruits;
+ (id)sharedManager;
#end
#import "MyManager.h"
static MyManager *sharedMyManager = nil;
#implementation MyManager
#synthesize fruits;
#pragma mark Singleton Methods
+ (id)sharedManager {
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
- (id)init {
if ((self = [super init])) {
fruits = [[NSMutableArray alloc] init];
}
return self;
}
-(void) dealloc{
self.fruits = nil;
[super dealloc];
}
#end
Now I'm using the following code so that I can use workouts in the new view
#import "MyManager.h"
#interface Chest : UIViewController {
IBOutlet MyManager *fruits;
}
#property (nonatomic, retain) IBOutlet MyManager *fruits;
-(IBAction) goToList: (id) sender;
#end
When a button is clicked, goToList is called, and I populate my array, fruits
#import "Chest.h"
#implementation Chest
#synthesize fruits;
-(IBAction) goToList:(id)sender{
MyManager *fruits = [MyManager sharedManager];
NSString *filePath;
NSString *fileContents;
filePath = [[NSBundle mainBundle] pathForResource:#"chest_strength" ofType:#"csv"];
fileContents = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
fruits = [fileContents componentsSeparatedByString:#"\n"];
}
When I output the elements of *fruits in this view, everything works fine. Now when I try to access this same variable in the other view, it says the array is null. Here's the code for the second view:
#interface List : UIViewController {
IBOutlet MyManager *fruits;
}
#property (nonatomic, retain) IBOutlet MyManager *fruits;
#end
#import "List.h"
#import "MyManager.h"
#implementation List
#synthesize fruits
NSLog(#"%#", fruits); //This is the part that isn't displaying correctly. I'm getting a null here
So my question is, how do I do this so that I can get the array fruits that I populated in Chest and use it in List so that I can display the contents of the array in that view?
Thank you to everybody who answers. This problem is seriously bogging me down and I need to finish this project ASAP. Much appreciated.
You've changed a few things in this question but the fundamental problem remains: the array is a property of your singleton, and you are not treating it as such.
Whenever you refer to the array, outside of the singleton, do it like this:
[MyManager sharedManager].fruits
If you are accessing it frequently, you can create a local ivar, but you certainly wouldn't have it as an IBOutlet, which you are doing in your last code sample. How is that ever going to be set?
I have a small piece of code that sets the NSString (strUsername) of the class Username to the value which is typed into a UITextField and then a button is pressed. This works fine:
UsernameViewController.m
#import <UIKit/UIKit.h>
#import "Username.h"
#interface UsernameViewController : UIViewController
{
Username *username;
__weak IBOutlet UITextField *test;
}
#property (nonatomic, retain)IBOutlet UITextField *txtUsername;
#property (nonatomic, retain) IBOutlet UITextField *test;
-(IBAction)setUsername;
#end
#import "UsernameViewController.h"
#import "Username.h"
#implementation UsernameViewController
#synthesize test=_test;
- (void)viewDidLoad
{
[super viewDidLoad];
username = [[Username alloc] init];
}
-(IBAction)setUsername
{
NSString *inputUsername = self.test.text;
NSLog(#"inputUsername is: %#", inputUsername);
username.strUsername = inputUsername;
NSLog(#"the username.strUsername is now: %#", username.strUsername);
}
My NSLog output shows that the UItextfield input and NSString setter are working:
LocNews1[6699:707] inputUsername is: Harry brown
LocNews1[6699:707] the username.strUsername is now: Harry brown
Now when it hit the back button on this view it return me back to a UITableViewController. I then perform a pull down to refresh action and its called the following method:
TestViewController.m (UITableViewController type)
#import "TestViewController.h"
#import "ViewController.h"
#import "DetailViewController.h"
#import "AppDelegate.h"
#import "NewsArticle.h"
#import "ResultsCustomCell.h"
#import "XMLParser.h"
#implementation TestViewController
//some code
- (void)addItem
{
username = [[Username alloc] init];
// Use XMLparser to check for updated new feeds.
if(username.strUsername != NULL)
{
NSLog(#"ViewController username.strUsername is:%#",username.strUsername);
activeUsername = username.strUsername;
}
else
{
NSLog(#"%#",username.strUsername);
activeUsername = #"";
}
NSString *myLat = [[NSString alloc] initWithFormat:#"%f", locationManager.location.coordinate.latitude];
NSString *mylong = [[NSString alloc] initWithFormat:#"%f", locationManager.location.coordinate.longitude];
XMLParser *parseQuestionnaire = [[XMLParser alloc] init];
NSLog(#"username %#",activeUsername);
newsArticle = [parseQuestionnaire parseXML:myLat:mylong:activeUsername];
[self.tableView reloadData];
[self stopLoading];
}
However this shows the NSLog output as:
LocNews1[6699:707] ViewController username.strUsername is:
As you can see the string has been set in UsernameViewController.m but when I try and call the string back in TestViewController.m is appears to be blank (there is no null in the NSLog, just blank);
What could be causing this?
EDIT: Username.h/m
#import <Foundation/Foundation.h>
#interface Username : NSObject
{
NSString *strUsername;
}
#property (nonatomic, retain) NSString *strUsername;
#end
#import "Username.h"
#implementation Username
#synthesize strUsername;
-(id)init
{
strUsername = [[NSString alloc] init];
return self;
}
#end
Note: Username is declared in both TestViewController.h and UsernameViewController.h like: Username *username;
The username instance variable in that instance of UsernameViewController is completely unrelated to the username instance variable in the instance of TestViewController. You'll need to store the variable in a place that both controllers know about or pass it between them if you want them both to have access. Simply having two variables with the same name doesn't connect them in any way.
I am new to arrays and objects. I have a class HowToPlay.h (of course that has a .m also) their i define two arrays
NSMutableArray *nibs;
NSMutableArray *unusedNibs;
#property (nonatomic, retain) NSMutableArray *nibs;
#property (nonatomic, retain) NSMutableArray *unusedNibs;
then we jump into the .m,
i write all the stuff for the arrays,
nibs = [[NSMutableArray alloc]initWithObjects:#"Question 2", #"Question 3", nil];
self.unusedNibs = nibs;
[nibs release];
Then i also have another class called Question 1, i need to be able to use this array in that class, and be able to change it, but keep the changes on the HowToPlay.m file.
here is why, basically this array loads random NIB files, and then deletes them from the array when they have been used.
in Question 1.m here is what im doing to use the array
random = arc4random() % [self.unusedNibs count];
NSString *nibName = [self.unusedNibs objectAtIndex:random];
[self.unusedNibs removeObjectAtIndex:random];
if (nibName == #"Question 3") {
Question_3 *Q3 = [[Question_3 alloc] initWithNibName:#"Question 3" bundle:nil];
Q3.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:Q3 animated:YES];
[Q3 release];
}
if (nibName == #"Question 2") {
Question_2 *Q2 = [[Question_2 alloc] initWithNibName:#"Question 2" bundle:nil];
Q2.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:Q2 animated:YES];
[Q2 release];
}
This all seems to work fine, but the problem im having is it seems that objects in the array are not getting deleted, even though this line runs
[self.unusedNibs removeObjectAtIndex:random];
I haved tried making it
[HowToPlay.unusedNibs removeObjectAtIndex:random];
I get a error saying expected '.' before '.' token
It seems to me that i have access to read the array, but not to change it. any way to fix this so i can change the array? thanks
UPDATE:
here is the whole HowToPlay.h file contents:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
int score;
int usedQ1;
int usedQ2;
int usedQ3;
NSMutableArray *nibs;
NSMutableArray *unusedNibs;
#interface HowToPlay : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> {
UIPickerView *selectType;
NSMutableArray *selectArray;
AVAudioPlayer *audioPlayer;
UIActivityIndicatorView *progress;
UIButton *worldButton;
UIButton *politicsButton;
UIButton *starButton;
}
#property (nonatomic, retain) NSMutableArray *nibs;
#property (nonatomic, retain) NSMutableArray *unusedNibs;
#property (nonatomic, retain) IBOutlet UIButton *worldButton;
#property (nonatomic, retain) IBOutlet UIButton *politicsButton;
#property (nonatomic, retain) IBOutlet UIButton *starButton;
#property (nonatomic, retain) IBOutlet UIPickerView *selectType;
#property (nonatomic) int usedQ1;
#property (nonatomic) int usedQ2;
#property (nonatomic) int usedQ3;
#property (readwrite) int score;
-(IBAction)World:(id)sender;
- (IBAction)Politics:(id)sender;
-(IBAction)Stars:(id)sender;
#end
#import "MainViewController.h"
#import "Question 1.h"
#import "Question 2.h"
#import "Question 3.h"
I import after because otherwise i get errors
Also I have the array set up on theViewDidLoad part of HowToPlay, is this a bad idea?
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
NSURL *click = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/click.wav", [[NSBundle mainBundle] resourcePath]]];
audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:click error:nil];
audioPlayer.numberOfLoops = 1;
progress = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
progress.frame = CGRectMake(0.0, 0.0, 30.0, 30.0);
progress.center = self.view.center;
[self.view addSubview: progress];
usedQ1 = 0;
usedQ2 = 0;
usedQ3 = 0;
selectArray = [[NSMutableArray alloc]init];
[selectArray addObject:#"World"];
[selectArray addObject:#"Politics"];
[selectArray addObject:#"Stars"];
score = 0;
nibs = [[NSMutableArray alloc]initWithObjects:#"Question 2", #"Question 3", nil];
self.unusedNibs = nibs;
[nibs release];
}
How do you check if objects are actually deleted? Please post some more code as the way you remove objects from unusedNibs seems to be fine. As per this code:
[self.unusedNibs removeObjectAtIndex:random];
and this code
[HowToPlay.unusedNibs removeObjectAtIndex:random];
The reason why you're getting this error is because you're trying to access unusedNibs using a class name "HowToPlay" instead of its instance "self".
A couple of things: first, to call properties like unusedNibs in HowToPlay it looks like you are calling the class and not an instance. You need to create a HowToPlay object and assign it to a property in your Question1 object so the question one Object has something to call to. Question1 should not call 'self' for unusedNibs since it does not own it.
With what you are doing it might make more sense to put the function figuring out the next random controller in the HowToPlay class. That way your question view controllers could just ask it to return which controller is next without having to duplicate that code across every question controller.
What am I doing wrong? My code crashes when I try to log the array. Here is my class:
#interface ArrayTestAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
NSArray *array;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) NSArray *array;
-(IBAction)buttonPressed;
#end
#implementation ArrayTestAppDelegate
#synthesize window, array;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
array = [NSArray arrayWithObjects:#"Banana", #"Apple", #"Orange", #"Pear", #"Plum", nil];
[window makeKeyAndVisible];
}
-(IBAction)buttonPressed {
NSLog(#"%#", array);
}
- (void)dealloc {
[window release];
[array release];
[super dealloc];
}
#end
This is a common memory management error in Cocoa. The arrayWithObjects method of the NSArray class returns an autoreleased object. By the time you try to log the array in the buttonPressed method, the array has already been released and you get a crash. The fix is easy:
array = [[NSArray alloc] initWithObjects:#"Banana", #"Plum", nil];
Or:
array = [[NSArray arrayWithObjects:#"Banana", #"Plum", nil] retain];
I guess the first one is better, the retain on the end of the second example is easy to miss. I would suggest that you read some more on memory management in Cocoa.