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.
Related
I can create the UIButton.
But the callback: target: object won't work within the current object. ??
I can only do "self.viewController" object, and can't do "self" for current object.
thx
#import <Foundation/Foundation.h>
#import "ViewController.h"
#class ViewController;
#interface CGuiSetup : NSObject
{
#public
ViewController *viewController;
}
- (void) Setup;
- (void) ButtonRespond:(UIButton*) btn;
#end
#import "CGuiSetup.h"
#implementation CGuiSetup
- (void) ButtonRespond:(UIButton*) btn
{
NSLog(#"ButtonRespond");
}
- (void) Setup
{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(10,10,100,100)];
// But I want to call the following in the CGuiSetup object (self) instead... but it crashes out if I leave it as just "self"
[btn addTarget:self.viewController action:#selector(ButtonRespond:)
forControlEvents:UIControlEventTouchUpInside]; //works: for "self.viewController" if I put ButtonRespond in the ViewController
[btn addTarget:self action:#selector(ButtonRespond:)
forControlEvents:UIControlEventTouchUpInside]; //fails: for "self"
[self.viewController.view addSubview:btn];
}
#end
#import <UIKit/UIKit.h>
#import "CGuiSetup.h"
#class CGuiSetup;
#interface ViewController : UIViewController
{
CGuiSetup *guiSetup; //<---- had to take this out of the "viewDidLoad" method
}
#end
- (void)viewDidLoad
{
[super viewDidLoad];
guiSetup = [CGuiSetup alloc];
guiSetup->viewController = self;
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(10,10,100,100)];
[btn addTarget:guiSetup action:#selector(ButtonRespond:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
If you're using ARC, does any object have a retaining reference to CGuiSetup? I sounds like CGuiSetup is instantiated, creates (or maybe receives from another object) the viewController, adds the button to it and then gives the view controller to another object (perhaps by pushing it on a navController or setting it to be the root controller of the app)? Whatever the case is, CGuiSetup it being dealloc'd and the button is trying to send a message to an object that's already been destroyed. How/where is CGuiSetup created? What object retains a reference to it? That's probably where your problem is.
If you don't understand what retain/release is and/or you don't know what ARC is, you need to read Apple's memory management guide: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
That's probably because your object is destroyed, while _viewController still has retain count greater than 0 (so it's not destroyed). Balance you're retain/release count.
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
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 :)
I have three IBActions, each linked with it's own button like so:
#import "Controller.h"
#import "Application.h"
#implementation Controller
- (IBAction)deal:(id)sender {
NSButton *deal = (NSButton *)sender;
...
}
- (IBAction)hit:(id)sender {
NSButton *hit = (NSButton *)sender;
...
}
- (IBAction)stay:(id)sender {
NSButton *stay = (NSButton *)sender;
...
}
#end
How do you use/call on a button outside it's scope? I'm looking to do something like this:
- (IBAction)hit:(id)sender {
NSButton *hit = (NSButton *)sender;
...
[hit setEnabled: NO];
[stay setEnabled: NO]; // Using/altering "Stay's" button
}
Thanks in advance!
IBAction is a typedef of void, used to flag up methods that you want Interface Builder (or Xcode 4's interface designer to spot. They're just ordinary methods with no outward link to anything.
What you probably want is some IBOutlets to connect out to the button. E.g. to connect to the hit button, you'd add this to your #interface:
IBOutlet NSButton *hit;
Then in Interface Builder or Xcode you should be able to control-drag a link from your class out to the button and connect the outlet — the opposite of what you've been doing to connect the button events to your class, effectively.
Because hit is an instance variable, you can access it from any method in your class.
You can declare a NSButton property as IBOutlet in your view controller and then in the Interface Builder you can link your button with it.
Something like:
#property (nonatomic, assign) IBOutlet NSButton * button;
I'm trying to subclass UIImageView to add some custom functionality in it. I started trying to do the basics, just init an object with a given image and display it on the screen.
Using UIImageView everything works fine, but if i change my object from UIImageView to my custom class, no image is displayed.
Here's what i've done so far:
//Imager.h
#import <UIKit/UIKit.h>
#interface Imager : UIImageView {
}
-(id) init;
-(void) retrieveImageFromUrl: (NSString *)the_URL;
#end
//Imager.m
#import "Imager.h"
#implementation Imager
#synthesize image;
-(id)init
{
self = [super init];
return self;
}
-(void) retrieveImageFromUrl: (NSString *)the_URL{
//Not implemented yet
}
#end
So, i am using this statment: cell.postImage.image = [UIImage imageNamed:#"img.png"];
Before this is executed, i also have postImage = [[UIImageView alloc] init];
If postImage is declared as UIImageView everything works as expected. But if i change it to Imager instead, then nothing is displayed.
What am i missing?
You're synthesizing image, thus blocking calls to setImage on the superclass (i.e. UIImageView) when you attempt to use the dot notation to set the image.
Remove this line:
#synthesize image;
I would suggest using an Objective-C "Category" instead of subclassing the UIImageView. As long as you don't have to add any member variables, a Category is a better solution. When you use a category you can call your extended functions on any instance of the original class (in your case UIImageView. That removes the need for you to consciously use your subclass anywhere you might want to use your new functions.
You can just do the following in a header:
#interface UIImageView (UIImageView+URL)
-(void) retrieveImageFromUrl: (NSString *)the_URL;
#end
Then in an implimentation file:
#implimentation UIImageView (UIImageView+URL)
-(void) retrieveImageFromUrl: (NSString *)the_URL
{
// implimentation
}
#end
Then wherever you want to use your new function on a UIImageView, you just need to include the header file.