Objective-C: Calling class 2 instance from class1 [alloc init] way is not working - objective-c

I've got the following method on a GameScreen.m file, with its own declaration - (void) drawNumbers on a GameScreen.h file:
//GameScreen.h
#import <UIKit/UIKit.h>
#interface GameScreen : UIView
{
IBOutlet UIButton *cell00;
}
- (void) drawNumbers;
- (IBAction) onCellClick:(id)sender;
#property (nonatomic, retain) IBOutlet UIButton *cell00;
#end
//GameScreen.m
#import "GameScreen.h"
- (void) drawNumbers
{
//testing if this works, so far it doesn't
[cell00 setTitle:#"Whatever" forState:UIControlStateNormal];
[cell00 setTitle:#"Whatever" forState:UIControlStateHighlighted];
}
I'm trying to call this method from my GameScreenViewController.m file, this way:
//GameScreenViewController.m
#import "GameScreenViewController.h"
#import "GameScreen.h"
...
- (void) viewDidLoad
{
GameScreen *aGameScreen = [[GameScreen alloc] init];
[aGameScreen drawNumbers];
[aGameScreen release];
[super viewDidLoad];
}
This is supposed to change the title of a button in a GameScreen.xib file where GameScreenViewController.m is the viewController and GameScreen class is the event handler where I get all the button clicks, timers running, etc. I am trying to call [drawNumbers] from [viewDidLoad] since I want the title to be changed when the screen is brought up front (screen management is done through the AppDelegate files).
The thing is, if I call drawNumbers instance from inside the same class through
//GameScreen.m
#import GameScreen.h
-(void) onButtonClick:(id)sender
{
//some other code
[self drawNumbers];
}
it works (as to say, nothing wrong with the code implementation or the graphic interface).
I've browsed through Apple Guide and tons of pages on the Internet, but I can't seem to find any light to this. Any further help (including answers as to where exactly find the answer in the ADG) would be really appreciated.
(Edited: here goes the AppDelegate code to flip to the specific view, just in case):
//myAppAppDelegate.h
#import <UIKit/UIKit.h>
#class myAppViewController, GameScreenViewController;
#interface myAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
myAppViewController *viewController;
GameScreenViewController *gameScreenViewController;
}
- (void) flipToGameScreen;
#property (nonatomic, retain) UIWindow *window;
#property (nonatomic, retain) GameScreenViewController *gameScreenViewController;
#end
//myAppAppDelegate.m
-(void) flipToGameScreen
{
GameScreenViewController *aGameScreenView = [[GameScreenViewController alloc] initWithNibName: #"GameScreen" bundle:nil];
[self setGameScreenViewController:aGameScreenView];
[aGameScreenView release];
[gameScreenViewController.view.frame = [[UIScreen mainScreen] applicationFrame];
[viewController.view removeFromSuperview];
[self.window addSubview:[gameScreenViewController view]];
}

Since your cell00 is to be set by a NIB it will be nil if you simply do [[GameScreen alloc] init]. It will only be set if the corresponding NIB is loaded (and a connection is actually set up).
If the cell can be accessed in your viewDidLoad, create a property on GameScreen and pass it through the property (or a dedicated initWithCell: or something).
If you have something like an IBOutlet GameScreen *aGameScreen; on your GameScreenViewController (and also established a connection to cell00 in the same NIB) you should access that instead.

Related

How to correctly implement a NSWindowController subclass with xib-file

I am trying to implement a NSWindowController subclass with new xib-file, I read up in lots of books, and researched on StackOverflow, but none of the steps provided made my window show, nor did the subclass code get executed. The new xib-file has its File's Owner set to "LogNavigatorController" and connections to the window and its contents have been made.
My AppDelegate.h:
#import <Cocoa/Cocoa.h>
#class LogNavigatorWindowController;
#interface AppDelegate : NSObject <NSApplicationDelegate>
{
LogNavigatorWindowController *logsWindowController;
}
#end
My AppDelegate.m:
#import "AppDelegate.h"
#import "LogNavigatorWindowController.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
logsWindowController = [[LogNavigatorWindowController alloc] initWithWindowNibName:#"LogNavigatorWindowController"];
[logsWindowController showWindow:self];
}
#end
My LogNavigatorWindowController.h:
#import <Cocoa/Cocoa.h>
#interface LogNavigatorWindowController : NSWindowController
{
NSArray *directoryList1;
NSArray *directoryList2;
NSMutableArray *directoryList;
NSMutableArray *filePaths1;
NSMutableArray *filePaths2;
}
#property (assign) IBOutlet NSWindow *window;
#property (weak) IBOutlet NSTableView *logsTableView;
#property (unsafe_unretained) IBOutlet NSTextView *logsTextView;
#property (assign) IBOutlet NSArrayController *LogListController;
#property (retain) NSMutableArray *logsArray;
- (void) myDirectoryLogFunction;
#end
My LogNavigatorController.m:
#import "LogNavigatorWindowController.h"
#interface LogNavigatorWindowController ()
#end
#implementation LogNavigatorWindowController
#synthesize logsTableView;
#synthesize logsTextView;
#synthesize window;
- (id)init
{
self = [super initWithWindowNibName:#"LogNavigatorWindowController"];
[self loadWindow];
[self showWindow:#"Log Navigator"];
[self.window makeKeyAndOrderFront:nil];
if (self)
{
// Initialization code here.
[self myDirectoryLogFunction];
}
return self;
}
- (void)windowDidLoad
{
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
- (void) myDirectoryLogFunction
{
NSLog(#"Code execution test successful");
}
#end
You don't need to create the window property since it is already available for NSWindowController subclasses. Maybe that causes the problem.
Also your init method contains a lot of code that doesn't belong there. Remove
[self loadWindow];
[self showWindow:#"Log Navigator"];
[self.window makeKeyAndOrderFront:nil];
as well as replace
self = [super initWithWindowNibName:#"LogNavigatorWindowController"];
with
self = [super init];
You may want to remove the init method at all, since you don't need it in your case.
and move
[self myDirectoryLogFunction];
to the windowDidLoad method.
Also always check that the code for instantiating the window controller (in your case from the app delegates didFinishLaunching: ) is called. Sometimes it helps to create a new project and test there, if you may have changed too much within the original project and by accident removed delegate connections or similar.

NSTextView string is null when calling from an other class

I'm a newbie in Cocoa
I have a function in a class call TextSaver.m :
- (void) save {
TheNotes *myNote = [[TheNotes alloc]init];
myNote.theText = [theTextView string];
NSLog(#"%#",myNote.theText);
[NSKeyedArchiver archiveRootObject:myNote.theText toFile:#"..."];
}
And I'm calling it from the AppDelegate with applicationWillTerminate :
- (void)applicationWillTerminate:(NSNotification *)notification{
[theTextSaver save];
}
But NSLog(#"%#",myNote.theText); results null... Like NSLog(#"%#",theTextView);. Which means when I call the function I can't access theTextView.
I've already try to call this function in the TextSaver.m class with a -(IBAction) and it worked!
Hope you can help me !
EDIT
The TextSaver is created with an #import TextSaver.h and in the appInterface
TextSaver *theTextSaver;
EDIT 2
I rewrite the code to make it simpler :
AppDelegate.h :
#import <Cocoa/Cocoa.h>
#import "TheNotes.h"
#interface AppDelegate : NSObject <NSApplicationDelegate>{
TheNotes *myNote;
}
#property (copy) TheNotes *myNote;
#property (assign) IBOutlet NSWindow *window;
#end
AppDelegate.m :
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize myNote;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
myNote = [[TheNotes alloc]init]; //Do I need to put it in -(id) init ?
}
- (void)applicationWillTerminate:(NSNotification *)notification{
[myNote save];
}
#end
TheNotes.h :
#import <Foundation/Foundation.h>
#interface TheNotes : NSObject {
NSString *theText;
IBOutlet NSTextView *theTextView;// Do I need to alloc memory ?
}
-(void) save;
#property (copy) NSString *theText;
#end
TheNotes.m :
#implementation TheNotes
#synthesize theText;
- (void) save {
NSLog(#"%#",theTextView.string);// Save is properly called, but this results (null).
[NSKeyedArchiver archiveRootObject:theTextView.string toFile:#"..."];
}
#end
The two questions you need to answer for yourself are:
Why do I expect my TextSaver to know about the text view?
Where do I tell the TextSaver about the text view?
The other possible answer to the first question is “the TextSaver created the text view”, but I'm assuming that's not the case.
So, you need to find where you think you're telling the TextSaver about the text view and make sure that's the case.
If you haven't done anything specific to tell the TextSaver about the text view, but rather are expecting it to just know about it, then that's probably the problem.
As Phillip Mills alluded to in his comment, merely declaring a variable named theTextView does not mean that the TextSaver knows about the text view. The compiler cannot read English: the names you choose are for your own benefit only; the compiler treats them only as identifiers. It does not see “theTextView” and go “oh, that! that's over there; I'll go get it”.
In order for theTextView to actually point to the text view, you need to put the text view there. You do this via assignment. Either expose theTextView as a property and set it from somewhere else, or set it internally within the TextSaver class (after either creating the text view yourself or getting it from another object).
I would make it a property (named simply textView) and set that property from whatever owns both the TextSaver and the text view.
This is a working example of basically what you're trying to achieve, HTH.
There are two classes, AppDelegate and TestViewController. TestViewController has a UITextView, whenever the user presses the home button of the device while editing the UITextView, the - (void)applicationDidEnterBackground:(UIApplication *)application method of the AppDelegate is called and the note is printed to the console (here you could save the note instead).
I use applicationDidEnterBackground because it's what is called when the app goes into background mode.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
PVSTestViewController *nextScreen = [[PVSTestViewController alloc] init];
self.delegate = nextScreen; // Assign TestViewController as the AppDelegate's delegate.
self.window.rootViewController = nextScreen;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.delegate saveData]; // Called when the user presses the home button.
}
AppDelegate.h
....
#protocol PVSAppDelegateProtocol <NSObject>
- (void)saveData; // Any class that conforms to our protocol must implement this method.
#end
#interface PVSAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, weak) id<PVSAppDelegateProtocol> delegate; // Here we store the delegate class.
#end
TestViewController.m
#import "PVSTestViewController.h"
#interface PVSTestViewController ()
#property (weak, nonatomic) IBOutlet UITextView *textView;
#end
#implementation PVSTestViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)saveData
{
// This is called by the AppDelegate when the app goes into the background.
NSLog([NSString stringWithFormat:#"Text is: %#", self.textView.text ]);
}
#end
TestViewController.h
....
#import "PVSAppDelegate.h"
#interface PVSTestViewController : UIViewController <PVSAppDelegateProtocol>
#end

obj-c : Cant change subView of viewcontroller with Notification

I'm confused about below situation.
I have a viewcontroller(VC), it has 1 subview(SubV) and 1 other class.(classA)
Also i have an event handler called from classA, i want this event handler to change my subV in VC.
When i access SubV from VC directly, it is OK, image of subview changed etc.
But when the classA triggers an event handler of VC, it reaches VC, also access subView's method but no change in my subView !!! (I also try delegate but the result is same)
ViewController.h
#interface ViewController : UIViewController {
.
IBOutlet SubView *subView;
ClassA *classA;
.
}
#property (retain, nonatomic) IBOutlet SubView *subView;
#property (retain, nonatomic) ClassA *classA;
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.subView = [self.subView init];
self.classA = [[ClassA alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(eventListener:) name:#"eventType" object:nil];
}
- (void) eventListener:(NSNotification *) not
{
[self.subView RefreshView]; // it doesnt work! calls refreshView method but no change
}
- (IBAction)buttonPressed:(id)sender
{
[self.subView RefreshView]; // it works perfect
}
SubView.h
#interface SubView : UIImageView
#property int state;
#property NSArray *imageArray;
- (void) RefreshView;
- (id) init;
#end
SubView.m
- (void) RefreshView{
[self stopAnimating];
self.imageArray = [NSArray arrayWithObjects:[UIImage imageNamed:#"a.png"], nil];
self.animationDuration = 1;
self.animationImages = self.imageArray;
self.animationRepeatCount = 0;
[self startAnimating];
}
ClassA.m
-(void)methodA{
[myEvent requestEvent];
}
So, what i am trying to do here is accessing & changing subView with a button in Viewcontroller and with a thread running in another classA
Edit: Not quite sure what to make of this. You've edited your post to the changes I proposed, making my answer look superfluous at best and deranged at worst...
You have created the class SubView as a subclass of UIImageView. But the IBOutlet *subView is not a member of class SubView but a member of UIImageView. I suspect this might carry over to the xib/storyboard as well(?) If so, this means that any messages you send to your subView instance will be handled by a stock UIImageView rather than your own class...
#property (retain, nonatomic) IBOutlet UIImageView *subView;
should probably read
#property (retain, nonatomic) IBOutlet SubView *subView;
Finally i've found the solution! Because of the thread that i run in ClassA, i should use '
[self performSelectorOnMainThread:#selector(myMethodToRefreshSubView) withObject:nil waitUntilDone:NO];
in my eventListener method.

mouseDown not firing properly on NSTextField

I tried implementing the second answer posted in this post here. I have the desire as the person asking the question however my mouseDown is not working/registering. Here is what I have.
AppDelegate.h
AppDelegate.m
MouseDownTextField.h
MouseDownTextField.m
and there relavent content:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "MouseDownTextField.h"
#interface AppDelegate : NSObject <MouseDownTextFieldDelegate> {
NSWindow *window;
IBOutlet NSMenu *statusMenu;
NSStatusItem *statusItem;
NSMutableArray *selector;
NSMutableArray *display;
NSTimer *timer;
MouseDownTextField *quoteHolder; }
#property IBOutlet MouseDownTextField *quoteHolder;
#end
AppDelegate.m
- (void)displayString:(NSString *)title {
NSRect frame = NSMakeRect(50, 0, 200, 17);
quoteHolder = [[MouseDownTextField alloc] initWithFrame:frame];
[[self quoteHolder] setDelegate:self];
[quoteHolder setStringValue:title];
[quoteHolder setTextColor:[NSColor blueColor]];
[test addSubview:quoteHolder];
[statusItem setView:test]; }
-(void)mouseDownTextFieldClicked:(MouseDownTextField *)textField {
NSLog(#"Clicked");}
MouseDownTextField.h
#import <Appkit/Appkit.h>
#class MouseDownTextField;
#protocol MouseDownTextFieldDelegate <NSTextFieldDelegate>
-(void) mouseDownTextFieldClicked:(MouseDownTextField *)textField;
#end
#interface MouseDownTextField: NSTextField {
}
#property(assign) id<MouseDownTextFieldDelegate> delegate;
#end
MouseDownTextField.m
#import "MouseDownTextField.h"
#implementation MouseDownTextField
-(void)mouseDown:(NSEvent *)event {
[self.delegate mouseDownTextFieldClicked:self]; }
-(void)setDelegate:(id<MouseDownTextFieldDelegate>)delegate {
[super setDelegate:delegate]; }
-(id)delegate {
return [super delegate]; }
#end
Thoughts on what could be wrong or what i have done wrong?
You are creating quoteHolder in IB, you should remove the following line of code and you should be fine.
quoteHolder = [[MouseDownTextField alloc] initWithFrame:frame];
The result of reassigning the NSTextField is that the one you are clicking is no longer the one registered with the delegate. No need to add it as a subview either, it's already been added to the view hierarchy in IB.
Also, make sure in IB, under Accessibility, "User Interaction Enabled" is checked for the NSTextField.
As for the follow up quesion, how could you have multiple of these?
If you were adding multiple NSTextField instances in IB, each would be referenced as a #property just as you did with quoteHolder. The linkage is done in IB like this linked answer.
These could all have the same delegate. When mouseDownTextFieldClicked: is pressed you could interrogate the NSTextField for a unique id which could be assigned in IB as well. Hope this helps.

How do we disable this button with no compiler error?

I am trying to improve myself in Objective-C and what I am on about is now modifying and changing and existed project. I did everything I wanted expect one thing. Theres an info button in my program and it doesnt related with .xib file. I tried to remove it but always my main.m gave error like SIGABRT (int retval thing.)
Here is the thing what I want to modify
http://i.stack.imgur.com/ZG51s.png // The picture of my program and info button
I am trying to remove the (i) button on the right-down corner.
Here's my code
This is my RootViewController.h
#import <UIKit/UIKit.h>
#class MainViewController;
#interface RootViewController : UIViewController {
IBOutlet UIButton *infoButton; //Silinecek
MainViewController *mainViewController;
}
#property (nonatomic, retain) MainViewController *mainViewController;
#end
This is my RootViewController.m
#import "RootViewController.h"
#import "MainViewController.h"
#implementation RootViewController
#synthesize mainViewController;
- (void)viewDidLoad {
MainViewController *viewController = [[MainViewController alloc] initWithNibName:#"MainView" bundle:nil];
self.mainViewController = viewController;
[viewController release];
[self.view insertSubview:mainViewController.view belowSubview:infoButton];
}
and also I tried to modify my AppDelegate h and m. Here they are ;
#import <UIKit/UIKit.h>
#class RootViewController;
#interface AppDelegate : NSObject <UIApplicationDelegate> {
IBOutlet UIWindow *window;
IBOutlet RootViewController *rootViewController;
}
#property (nonatomic, retain) UIWindow *window;
#property (nonatomic, retain) RootViewController *rootViewController;
#end
#import "AppDelegate.h"
#import "RootViewController.h"
#implementation AppDelegate
#synthesize window;
#synthesize rootViewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:[rootViewController view]];
//[window makeKeyAndVisible];
}
/*
- (void)dealloc {
[rootViewController release];
[window release];
[super dealloc];
}
*/
What should I do for removing that info button in my View. Thanks for the any tips
And if you are interested in this is the whole algorithm : http://pastebin.com/hHQkQYS6
Do you still have the control linked somewhere in your xib file? It is declared as an IBOutlet control. Usually when I have these controls I will use the GUI link this control in some way (I can't remember what exactly as I have not done Obj-C in a long time). But I would definitely have a look around you xib file (as well as removing [self.view insertSubview:mainViewController.view belowSubview:infoButton];
The exception mentions:
[<RootViewController 0x4b9ab20> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key infoButton.
The call stack shows that it is thrown by UINib. So this is happening during nib load. So check for all objects present, carefully, in the nib and remove the info button