Set label text from different from class file - objective-c

What I would like the code to do is so when the button is pressed it runs the function in the Label.m file and it then sets the labels text to "test". Whenever I run it the code calls the function but doesn't change the labels text. Can someone please help me fix my code or show me the correct and easiest way to change a labels text from a class file.
In my FirstViewController.h
#interface FirstViewController : UIViewController{
IBOutlet UILabel *test;
}
#property (nonatomic, retain) IBOutlet UILabel *test;
In my FirstViewController.m
#import "Label.h"
-(IBAction)refresh:(id)sender {
[Label getSchedule];
}
In my Label.h
#import "FirstViewController.h"
#interface Label : NSObject
+ (void)getSchedule;
#end
In my Label.m
#import "FirstViewController.h"
#implementation Label
+ (void)getSchedule{
NSLog(#"log");
FirstViewController *VC = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
VC.test.text = #"test";
}
#end

Edit: As Maddy mentioned in the comments the original posters code would have worked if it was just called after the viewController had gotten all of its view objects. The easy way to achieve what the original poster wanted would be to simply add:
self.test.text = #"test";
to the viewControllers viewDidLoad method.
I'll leave my original answer here anyway, as I believe it improves on the original posters code and removes some of its dependencies. It still is way too complicated for what it wants to achieve but the pattern as such could be transferred to more befitting scenarios:
To elaborate on my comment:
Your method
+ (void)getSchedule{
NSLog(#"log");
FirstViewController *VC = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
VC.test.text = #"test";
}
Is a class method. So, naturally it is fired, but your UILabel instance test this instance have no idea about this. Furthermore you seem to have created your own class Label which subclasses NSObject, but the actual label instance is a regular UILabel.
I would guess what you are trying to do is something like this:
#interface Label : UILabel
- (void)getSchedule;
#end
...
#interface FirstViewController : UIViewController
#property (nonatomic, retain) IBOutlet Label *test;
Edit: forgot the method(!)
- (void)getSchedule{
self.text = #"test";
}
And finally in your viewController...
#import "Label.h"
-(IBAction)refresh:(id)sender {
[self.test getSchedule];
}

Related

Objective-c - control outlet from other class

I just like to play with coding for a hobby, so probably a noob question;
I have a simple storyboard for MacOS with 2 views. Both have there own classes (main class and subclass). How can I control a outlet in the subclass from the main class?
for example
I have a button (IBAction) in the mainclass and a textfield (IBOutlet) in the subclass. I want to set the stringvalue for the textfield with a click on the button in main.
I have searched a lot last days but just don't get it. (or just need a push in the right direction)
EDIT after JingJingTao's answer:
I used the control-drag function to open the second window.
I tried the code JingJingTao gives, but the textfield doesn't respond to the action.
My classes look like this now:
ViewController.h
#import <Cocoa/Cocoa.h>
#interface ViewController : NSViewController
- (IBAction)newText:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
#property (nonatomic) ViewController2 *subclass;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
}
- (void)newText:(id)sender {
self.subclass.textField.stringValue = #"button pressed";
}
#end
ViewController2.h
#import "ViewController.h"
#interface ViewController2 : ViewController
#property (nonatomic) IBOutlet NSTextField *textField;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
}
#end
Update:
I've attached two screenshots of what it looks like in the storyboard for the first suggestion,
1) Add a view to your ViewController, set the class at the top right to 'YourView', 'YourView' is a just an NSView, add a textfield to it and hook it up.
2) Add YourView as a property to your ViewController, i.e. #property (nonatomic) IBOutlet NSView *yourView; and hook it up.
Let me know if there are any issues.
You just need to put the textfield in the public interface of your subclass, so you can access it in your main class, although it does sound like you're using inheritance and I don't think you need to but that's another topic :D.
Example:
In MainClassViewController.m
#interface MainClassViewController ()
#propert (nonatomic) Subclass *subclass;
#end
#implementation MainClassViewController
// I guess you already add your subclass to the main viewcontroller because they display on the same screen.
- (void)yourButtonTapMethod {
self.subclass.textfield.text = #"Your value";
}
In Subclass.h
#interface Subclass : NSObject
#property (nonatomic) IBOutlet UITextfield *textfield;
I use Cocoa Touch instead of Cocoa, so maybe it's NSTextfield for you. Please let me know if this does not answer your question, good luck.

Data encapsulation, Instance variable cannot be accessed

I'm having some trouble understanding what classes can read what variables in other classes. I've read to many different things online and cant seem to find anything solid in here. I've literally wasted the past two days trying to get my program to work but no classes can read any other classes variables. Any help will be GREATLY appreciated.
This is my ViewController.h:
#interface ViewController : UIViewController
{
#public
NSString *nameOfLabel;
}
#property (strong, nonatomic) IBOutlet UILabel *firstLabel;
- (IBAction)Switch:(id)sender;
- (IBAction)changeLabel:(UIButton *)sender;
-(NSString *) nameOfLabel;
#end
nameOfLabel is a public variable and should be able to be accessed by an outside class, right?
ViewController.m:
#import "ViewController.h"
#import "NewView.h"
#interface ViewController ()
#end
#implementation ViewController
- (IBAction)Switch:(id)sender {
NewView * new = [[NewView alloc] initWithNibName:nil bundle:nil];
[self presentViewController: new animated:YES completion:NULL];
}
- (IBAction)changeLabel:(UIButton *)sender {
nameOfLabel = #"Test Name";
_firstLabel.text = nameOfLabel;
}
-(NSString *) nameOfLabel {
return nameOfLabel;
}
#end
changeLabel button changes *firstLabel.text to "Test name".
second class is NewView.h:
#import "ViewController.h"
#interface NewView : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *secondLabel;
- (IBAction)changeSecondLabel:(UIButton *)sender;
#end
and NewView.m:
#import "NewView.h"
#interface NewView ()
#end
#implementation NewView
{
ViewController *view;
}
- (IBAction)changeSecondLabel:(UIButton *)sender {
view = [[ViewController alloc] init];
_secondLabel.text = view.nameOfLabel;
}
#end
changeSecondLabel should change secondLabel.text to nameOfLabel which is 'Test name', however, the label actually disappears which makes me think that nameOfLabel cannot be reached. Ive played around with nameOfLabel, making it a #property and then synthesising it, as well as trying putting it in { NSString *nameOfLabel; } under #implementation but I still get the same result.
This line: view = [[ViewController alloc] init]; creates a new ViewController which doesn't know anything about what you may have done to some other ViewController. In your case, it specifically doesn't know that changeLabel: was called on another ViewController before this new one ever existed.
When the second view controller (NewView) is presented, it has no reference to the first view controller (ViewController) and it's data.
Here are a couple of suggestions.
In modern Objective-C I'd recommend using properties instead of exposing a variable.
Look over the naming in general. "ViewController" is not a good name for example.
If the property is part of an internal state of the class, declare it in a class extension.
Before you present the second view controller, set a reference to the string from the first view controller.
Part of ViewController.m:
#interface ViewController ()
#property (copy,nonatomic) NSString *nameOfLabel;
#end
#implementation ViewController
- (IBAction)Switch:(id)sender {
NewView *new = [[NewView alloc] initWithNibName:nil bundle:nil];
new.secondLabel.text = self.nameOfLabel;
[self presentViewController: new animated:YES completion:NULL];
}
First of all please read about coding standards, it's not a good practice to:
Name variables like "new"
Name methods like "Switch"
Name UIViewController like "view" or "NewView"
Regarding logic:
This is all messed up here. What you actually do is you create viewController with nameOfLabel which is empty and is only changed on button press. I assume you press that button so it's changed. Then on switch action you create another viewController and present it. Then from inside that new viewController you create another new viewController which has empty nameOfLabel, get this empty value and put it inside secondLabel.
There are couple of ways you can do to change secondLabel:
Move nameOfLabel to model and read it from there when you want to change secondLabel,
Because your new viewController is child of viewController that keeps nameOfLabel you can access it by calling [[self presentingViewController] nameOfLabel] but make it property first,
Pass nameOfLabel through designated initializer.
Well, if you want a simple demonstration of access of a public ivar, the syntax is:
view->nameOfLabel;
^^
not dot-syntax:
view.nameOfLabel;
(dot-syntax just goes through accessor methods).
I've only seen a handful of warranted edge cases over the years; there's rarely, rarely ever a good reason to make an ivar public (also, protected is also rarely a good choice).

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

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

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.

Editing a UIViewController from another class

I am trying to programmatically change the user interface of a UIViewController from another NSObject class. The problem is that I am unsure of how to access the UIViewController's view from the NSObject class. So for example, in my NSObject class, I say something like:
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
self.view.backgroundColor = [UIColor yellowColor];
but I keep getting errors saying "Request for member "view" in something not a strut or union." Is there something I need to allow my NSObject class to see my UIViewController?
Whenever you say "self" in a method, it refers to whatever object owns that method. So when you say self.view, you are really asking for the NSObject's view (which, needless to say, doesn't exist, unless you have specifically subclassed the NSObject to have a "view" property.
What you should do is give the NSObject class a property called myController or something in its interface declaration, or pass a ViewController* to any methods that need to access it.
For the property, you can say:
ViewController* myController;
in the NSObject sub-class interface declaration, or for the method way, add an argument to your NSObject sub-class' method:
- (void) someMethodThatTakesAViewController: (ViewController*) theViewController {
//Do your stuff here
theViewController.view = [[UIView alloc] init]; // Or whatever you want to do
}
Hope this was what you were looking for.
In the header file for the object that is trying to change the view, add #class <YOURVIEWCONTROLLER>;, then in the #interface section, add <YOURVIEWCONTROLLER> *viewController; then outside #interface add #property (nonatomic, retain) <YOURVIEWCONTROLLER> *viewController;. Then in the main file add #synthesize viewController; and #import "<YOURVIEWCONTROLLER.h". Then, to change the background colour, use viewController.view.backgroundColor = [UIColor <COLOUR>];.
e.g:
Test.h:
#import <UIKit/UIKit.h>
#class Test2ViewController;
#interface Test : UIViewController {
Test2ViewController *viewController;
}
#property (nonatomic, retain) Test2ViewController *viewController;
Test.m:
#import "Test.h"
#import "Test2ViewController.h"
#implementation Test
#synthesize viewController;
...
viewController.view.backgroundColor = [UIColor yellowColor];
...
Hope this helps
Edit: Make sure to call [viewController release] in your dealloc, otherwise you will have a leaky pipe ;)
you can't access like this... you need to somehow pass UIViewController's view in your NSObject class...
You can typecast your id to UIViewcontroller, like
[((UIViewController *)yourID).view addSubview:yourView.view];