Local Variables in viewdidload - objective-c

I'm currently trying to make a program when I create a button, and when I click it its alpha goes to zero. It may seam simple, but its driving me crazy.
You see, in my final project I'm making a lot of buttons so I need to do this all in code and not using story board.
Heres what I have so far
//mediumboard.h
#import <UIKit/UIKit.h>
#interface MediumBoard : UIViewController
#property (weak, nonatomic) IBOutlet UIScrollView *ScrollMedium;
#end
And in the implementation
- (void)viewDidLoad{
UIButton *Button1x1x1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[Button1x1x1 addTarget:self action:#selector(Press1x1x1) forControlEvents:UIControlEventTouchUpInside];
Button1x1x1.frame = CGRectMake(50,50, 80, 130);
[self.view addSubview:Button1x1x1];
}
Up in till now it works fine. It creates the button and displays it on my screen.
However when I try to implement this
-(void)Press1x1x1 {
Button1x1x1.alpha = 0;}
It gives me the error "Use of undeclared identifier 'Button1x1x1'"
I know its a variable localization problem, and that the variable Button1x1x1 is localized in viewdidload, but I have no idea how to solve this problem. Do I make it global variable? Please remember I can't use the Storyboard.
Additional info: I have no other references to Button1x1x1 in my code, anywhere.

You could use a selector that passes the sender as an argument.
[button1x1x1 addTarget:self action:#selector(press1x1x1:) forControlEvents:UIControlEventTouchUpInside];
// ^ emphasized
-(void)press1x1x1:(UIButton *)sender {
sender.alpha = 0;
}
and you should change your variable names so they start with a lowercase letter. Capital letters should only be used for class names.

You don't have to declare a global variable, just declare it as an instance variable like so:
#interface MediumBoard : UIViewController {
#private
UIButton *myButton_; // Or Button1x1x1, whatever you want to call it
}
#property (weak, nonatomic) IBOutlet UIScrollView *ScrollMedium;
#end

Related

Expected identifier or '(' - Xcode mistake

- (IBAction)button:(id)sender {
struct label.text =
}
Whats the problem?
Why does Xcode say:
"Expected identifier or '('?"
Hopefully you have hooked up your button correctly, are you using storyboards? If you are just drag a button and a label out to the storyboard. Open the assistant editor, it's a button that looks like a tux up in the right hand corner. You need to declare what your items will do. In the assistant open your .h file. Control drag from the label to the .h and select outlet. Call it label it you wish. Then control drag from the button and select action. Call that button if you wish. This is what your .h file should look like.
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
- (IBAction)button:(id)sender;
#end
Then in your .m file you should make it look like.
import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)button:(id)sender {
_label.text = #"Hello";
}
#end
I did this and when I touched the button the text changed from label to Hello. You also forgot the colon at the end.
You need to go back to your resources where you learned Objective-C and Cocoa, what you have is wrong in fundamental ways that show you don't understand the language at all
struct label.text =
This looks like just random tokens.
It looks like XCode is simply getting confused because the syntax of your statement is wrong. It looks like the line struct label.text = is trying to define a variable of type struct with the name label.text.
In Objective-C, the dot operator lets you access a method or property of an object. Trying to do this in the name of the variable doesn't make sense.

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).

Add NSString category extension to UIButton

I would like to extend UIButton with an NSString for some meta info. How could I do this?
I am starting with this:
#interface UIButton (neoUtils)
+ (UIButton *)neoName:(NSString *)buttonName;
#end
and the .m
#import "UIButton+NAME.h"
#implementation UIButton (neoUtils)
+ (UIButton *)neoName:(NSString *)buttonName {
UIButton *button = [UIButton neoName:buttonName];
NSLog(#"%#",button);
return button;
}
#end
Is this on the right path? And if so - how would I possibly use it?
I am assuming that
#interface UIButton (neoUtils)
is declared in UIButton+NAME.h.
First of all, looks like that program will enter a recursive loop as soon as you call that method:
+ (UIButton *)neoName:(NSString *)buttonName {
UIButton *button = [UIButton neoName:buttonName]; // <- this one
NSLog(#"%#",button);
return button;
}
because it will recurevely call the method itself.
Anyway, considering the extended object has to have a state (the NSString for the meta info has to be "remembered") I don't believe it's possible to fulfill the requirement with a category, that just extends the behaviour of the class. Then your solution didn't start on the right step I guess.
Instead I vould just create a class like
#interface XYMetaInfoButton : UIButton
#proerty (nonatomic, [strong|retain]) NSString *name;
#end
That you can then import globally in the project to have the new UIButton with meta-info.
But that's just a possibility, maybe someone has a better solution.

Programmatically create UIButton - won't call action?

I have a custom class, and that class has a UIButton instance variable. I have added this code in the class designated initializer:
theFishDeathView = [UIButton buttonWithType:UIButtonTypeCustom];
[theFishDeathView setFrame:CGRectMake(15, 15, 50, 50)];
[theFishDeathView setImage:[UIImage imageNamed:#"Small fish - death.png"] forState:UIControlStateNormal];
So this should properly allocate / initialize the button. And truly enough, the button get's displayed on the screen when this is called (and of course added as a subview).
Now, I call this method on my object:
[theFishDeathView addTarget:self action:#selector(sellFish) forControlEvents:UIControlEventTouchDown];
And here is the sellFish method:
-(void) sellFish {
thePlayer.dollars += worthInDollars * 3;
[theFishDeathView removeFromSuperview];
}
But when I try and press the button, it doesn't call that method. Am I missing something here?
For the sake of completeness, here is the Fish.h file. It is clear that theFishDeathView is an instance member of the Fish object.
#import <Foundation/Foundation.h>
#interface Fish : NSObject
{
float cookingTime;
float weight;
int worthInDollars;
NSString *name;
NSArray *animaionImages;
int fishMovementSpeed;
}
// Will be used to display
#property (nonatomic, retain) UIImageView *theFishImageView;
#property (nonatomic, retain) UIButton *theFishDeathView;
// Create setter / getter methods
#property (nonatomic, retain) NSString *name;
#property (readonly) int worthInDollars;
#property (readonly) int fishMovementSpeed;
-(id) initWith: (NSString *)theName andWeight: (float)theWeight andCookingTime: (float)theCookingTime andValue: (int)theValue andMovementSpeed: (int)speed;
-(CGRect) newFrameWithWidth:(int)width andHeight:(int)height;
-(void) killFish;
// Cooking methods
-(void) startCooking;
-(void) isDoneCooking;
-(void) isOverCooked;
-(void) sellFish;
#end
try
-(void) sellFish:(id)sender
and (with the : after sellFish)
[theFishDeathView addTarget:self
action:#selector(sellFish:)
forControlEvents:UIControlEventTouchUpInside];
[theFishDeathView addTarget:self
action:#selector(sellFish)
forControlEvents:UIControlEventTouchUpInside];
you wrote UIControlEventTouchDown not UIControlEventTouchDown
I wanted people to know i found the error (with some help from the Apple developers forum) - it was a memory leak. I was trying to send a message to a zombie object (i.e a deallocated object). I thought it was retained by adding it as a subview, but i totally forgot it was the BUTTON i added as a subview, and NOT the class that contained the button. So the class itself got deallocated, and the button was retained, he's the reason why i could still press it.
For others dealing with similar issues, turn on the Zombie Objects Enabled thing in the plist.info file. That way, you will get an error message like this: "Trying to send action to deallocated object".
Thanks for trying to help me out :)

Setting the initial value of a UILABEL

I'm trying to create a simple Quiz app (I'm a beginner), when I launch the app I want a UILabel to show the first question (of an array of questions). I'm having some trouble with setting the initial value.
I've done a couple of attempts, whiteout success. I my QuizAppDelegate.h file I declare my UILabel like this:
IBOutlet UILabel * questionField;
In my main .m file I have tried the following:
- (id)init {
[super init];
questions = [[NSMutableArray alloc] init];
// Not working
questionField = [[UILabel alloc] init];
[questionField setText:#"Hello"];
// Working
NSLog(#"Hello");
[self defaultQuestions];
// [self showQuestion];
return self;
}
Another thing I have tried is the following in QuizAppDelegate:
#property (nonatomic, retain) IBOutlet UILabel *questionField;
- (void)changeTitle:(NSString *)toName;
And in the .m file:
#synthesize questionField;
- (id)init {
[super init];
questions = [[NSMutableArray alloc] init];
// Not working
[self changeTitle:#"Hello"];
// Working
NSLog(#"Hello");
[self defaultQuestions];
// [self showQuestion];
return self;
}
-(void)changeTitle:(NSString *)toName {
[questionField setText:toName];
}
Any tips on how to solve this would be great!
// Anders
Hopefully you're not actually putting code into main.m. On iOS, you rarely modify that file.
Since you're doing everything in the AppDelegate, let's keep it there (as opposed to creating a new UIViewController). Let's start with the basics.
Adding the Label as an instance variable
You're doing this correctly—inside the curly braces of the .h file, put the line
IBOutlet UILabel * questionField;
Then, declare the corresponding property, and make sure to synthesize it in the .m file.
#property (nonatomic, retain) IBOutlet UILabel *questionField;
#synthesize questionField // in the .m file
Adding the UILabel in Interface Builder
Open up MainWindow.xib. Drag a UILabel from the Library to the Window that represents your app's window. Then Control-Drag from the AppDelegate object (the third icon on the left in Xcode 4; it'll be labelled in the Document window in IB 3). You'll see a little black window come up—select the option called questionField to make the connection.
See this link for screenshots and how to make connections in IB. The same applies in Xcode 4.
Changing the text
You don't need a separate method to change the text—just modify the label's text property.
Pick a method that'll be called when the app launches (applicationDidFinishLaunching:WithOptions: is a good place to do it in), and put the following code:
questionField.text = #"Hello";
And that's it!
Code
QuizAppDelegate.h
#import <UIKit/UIKit.h>
#interface QuizAppDelegate : NSObject <UIApplicationDelegate> {
IBOutlet UILabel *questionField;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UILabel *questionField;
#end
QuizAppDelegate.m
#import "QuizAppDelegate.h"
#implementation QuizAppDelegate
#synthesize window=_window;
#synthesize questionField;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Add the tab bar controller's current view as a subview of the window
[self.window addSubview:self.questionField];
[self.window makeKeyAndVisible];
self.questionField.text = #"Hello";
return YES;
}
- (void)dealloc
{
[_window release];
[questionField release];
[super dealloc];
}
#end
If you're creating the label programmatically, then you have to add the label to the view:
[self.view addSubview:questionField];
This assumes that you have a ViewController. If not, and you're doing this directly in the AppDelegate (a very bad idea, by the way), then do
[self.window addSubview:questionField];
If you're creating it in the IB, make sure you set up the connections.
You should not both add the UILabel in the IB and instantiate it programmatically. Only call alloc if you are creating it programmatically. Otherwise, if using the IB, skip that part. You created it already with the xib.
I suspect that you have either not created your Interface Builder layout properly - either you have missed the control out all together or more likely you have not connected that control to the questionField outlet in yout header file.
You need to drag a UILabel view into the main view and then connect it to the correct line in your header file.
You shouldn't be using your main.m like that at all. In fact, you should almost certainly never do anything with it. Try creating a UIViewController subclass and practicing your quiz with that. (Add the UILabel to the IB file and then connect the outlet.) Perhaps use the View-Based Application template while you are practicing.
This is a good answer:
"You're doing this correctly—inside the curly braces of the .h file, put the line
IBOutlet UILabel * questionField;"
I was trying to change the value of mylabel.text and the screen didn't update the label with this.value. I included the {IBOutlet UILabel * mylabel} and it works like a charm!
So this answer is valid to change the text of a label programmatically!
Thanks