I have a view controller with different buttons with background images assigned. My header file looks as follows:
#interface ImageSelect : UIViewController
- (IBAction)ImageButton:(id)sender;
- (IBAction)Done:(id)sender;
#property(nonatomic, readonly, retain) UIImage *currentImage;
#end
And the section of my main file that contains the button method looks like:
- (IBAction)ImageButton:(id)sender {
if ([#"railway-336702_1280.jpg" isEqual:self.currentImage]) {
img = #"railway-336702_1280.jpg";
NSLog(#"Test");
}
}
I am wanting to save the image name to a NSString called img. Currently, the code runs but doesn't actually perform the save to img.
A simpler way would be: if you simply wanted to check whether the UIButton contains that image that you set, you could simply use the tag property:
Let say you set its image with an image named: railway-336702_1280.jpg
Set the tag with something simpler like "1280".
Then check this tag against an Integer. And should you change the image again, change the tag correspondingly.
if (((UIButton*)sender).tag == 1280)
{
// Do stuff
}
Once a UIImage is created it loses all connection to the file it was loaded from. You cannot determine at runtime what the background image is.
If you need to get the name at runtime, subclass UIButton and then create a property called imageName and set it using the User Defined Runtime Attributes through Interface Builder.
Example:
In ImageSelectButton.m:
#interface ImageSelectButton ()
#property(nonatomic, retain) NSString *imageName;
#end
In ImageSelect.m:
#interface ImageSelect
...
- (IBAction)ImageButton:(ImageSelectButton*)sender {
if ([sender.imageName isEqualToString:#"railway-336702_1280.jpg"]) {
// Do stuff
}
}
...
In Interface Builder when selecting your UIButton set the Custom Class and runtime attribute:
Related
I am trying to create or change a UIimage from another class using a class method. however when I try to address the view in the class controller I can't. e.g. [self.view addsubview:...] is this possible ? what would be the best way to do this ? Thanks in advance.
You import the header file of your UIImage (or better use UIIMageView) in the second class, then define it as an object. Add #property and #synthesize is the second .m. The reference shoul work after as addSubview will know about imported object.
Lets say this is your model class header file and you define your uiimageview:
#property (weak,nonatomic) IBOutlet UIImageView *modelImageView;
and this is your view controller and its implementation file you may use like this:
#import "YourModel.h"
#interface yourViewController() {
YourModel *yourModel;
}
end
#implementation yourViewController
- (void) viewDidLoad {
[super viewDidLoad];
[self.view addSubView:yourModel.modelImageView];
}#end
That was straight way to do and to make something better; just define some methods which controls your UIImageViewlike changeColor setBackgroundColor etc. and reach them from your viewController just using for example:
[yourModel setColor:[UIColor greenColor] placeHolderImage:[UIImage ...]];
So what I'm trying to explain in here you can reach your UIImageView wherever you want and you will just have one Model is reachable from every viewController.
I have custom UIButton which programmatically interacts (triggers) with ViewController methods via protocol. But the behaviour of the button has to be dependent on the ViewController placed on. I do this to minimise amount of code in ViewControllers itself, as the button has to remain the same and bear the same functions (navigation).
Is there any way in UIButton's custom class to get the ViewController it is placed on?
I'd follow #rmaddy advice in a specific way, borrowing from the SDK's style
// MyCutomButton.h
#protocol MyCustomButtonDatasource;
#interface MyCustomButton : UIButton
#property(weak,nonatomic) IBOutlet id<MyCustomButtonDatasource>datasource;
// etc
#end
#protocol MyCustomButtonDatasource <NSObject>
#optional
- (NSString *)howShouldIBehave:(MyCustomButton *)button;
#end
Now the button can have it's datasource set in IB. View controllers that include it will need a little additional code (sorry, it's unavoidable in a good design). They will declare themselves as implementing MyCustomButtonDatasource.
When MyCustomButton needs to behave conditionally based on where it's placed, it can ask its datasource...
// MyCustomButton.m
NSString *string = #"defaultBehavior"; // per #RichardTopchiy's suggestion
if ([self.datasource respondsToSelector:#selector(howShouldIBehave:)])
string = [self.datasource howShouldIBehave:self];
// string is just made-up here, have it answer something simple (int, BOOL)
// that lets the button proceed with the right behavior. Don't ask for
// anything that relies on specific knowledge of how MyCustomButton
// is implemented
EDIT - To create the relationship, if you've decorated the property as an IBOutlet (as shown above), you should be able to setup the relationship in IB. Declare your view controller as implementing <MyCustomButtonDatasource>. Select your custom button, then the connections inspector, then drag to your view controller.
Alternatively, make the button itself an IBOutlet property in the view controller and, in viewDidLoad, do:
self.customButton.datasource = self;
The last way to do it is give your button a tag, say, 128, then:
MyCustomButton *customButton = (MyCustomButton *)[self.view viewWithTag:128];
self.customButton.datasource = self;
This is a trick I use a lot in android:
I take an image with Image Picker: camera or gallery
I put the image in an ImageView
I also put the image url in the ImageView, in the tag field
so later when I need the url of an image (to send to server), I grab it from the imageView's tag.
But tag in iOS is a bit different from android: in iOS it's just a number. So is there such a way of piggybacking on an UIButton on iOS: basically any field whatsoever that is available for storing a text and which the user cannot see?
I'm not aware of an analogous field on a UIImageView. Your best bet may be to subclass UIImageView to add such a property. In the .h file for the new class, do something like:
#interface SubclassedUIImageView : UIImageView
#property (strong, nonatomic, copy) NSString *url;
#end
Then assign the url value to SubclassedUIImageView in imagePickerController: didFinishPickingMediaWithInfo:. Assuming you're using Interface Builder, to use the subclassed UIImageView, you drop a UIImageView control onto the parent view, go to the Identity inspector, and change the Custom Class field to the name of your subclassed UIImageView.
Natively, there's no way to do this. However, you can use a category and store the text in an associated object:
#interface UIImageView (StringTagAdditions)
#property (nonatomic, copy) NSString *stringTag;
#end
#implementation UIImageView (StringTagAdditions)
static NSString *kStringTagKey = #"StringTagKey";
- (NSString *)stringTag {
return objc_getAssociatedObject(self, kStringTagKey);
}
- (void)setStringTag:(NSString *)stringTag {
objc_setAssociatedObject(self, kStringTagKey, stringTag, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
#end
More info # http://nshipster.com/associated-objects/
This type of thing has been asked before, but you could pull this off with a UIButton category that adds getter/setter like methods that store this value for you:
setting new properties in category interface/implementation
Objective-C: Property / instance variable in category
http://iosdevelopertips.com/objective-c/adding-properties-category-using-associated-objects.html
Or you could subclass UIButton and add the property you need. There are lots of options, but I'm unclear on what you mean by "the user cannot see"?
I am just start studying iOS developing watching Stanford iOS course, but it looks like I have already missing something.
I have a form with UILabel and UIButton. When an user press the button the title of the button must be added to the text of label.
Here is my current CalculatorViewController.h:
#import <UIKit/UIKit.h>
#interface CalculatorViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *display;
#end
and here is a CalculatorViewController.m:
#import "CalculatorViewController.h"
#implementation CalculatorViewController
#synthesize display = _display;
- (IBAction)digitPressed:(UIButton *)sender {
NSString *digit = [sender currentTitle];
UILabel *myDisplay = self.display;
myDisplay.text = [myDisplay.text stringByAppendingString:digit];
}
#end
The problem is that self.display (and myDisplay) variables have a nil value. Looks like I need to do something to link my variable with control on the form. What ?
Thanks in advance.
You need to link the control, the UILabel in Interface Builder to the variable in your CalculatorViewController class.
It is very likely that the file's owner (talking about the Xib file) is your CalculatorViewController, so you need to Control+drag the file's owner (or the object representing your VC) to the control and you will be shown a menu with the possible IBOutlet variables declared in your class, so you select the one you want to represent the control.
You can check if this link is properly set in two ways: (1) Select the UILabel in Interface Builder and see if there's a connection to the variable in the Connections Inspector, or (2) In your code you'll see a bullet near the IBOutlet declaration, if the bullet is hollow the connections is not set, if the bullet is filled the connection is set.
There is no need of this line
UILabel *myDisplay = self.display;
You have already declared your label in your interface file
- (IBAction)digitPressed:(UIButton *)sender
{
NSMutableString *string = [myDisplay.text stringByAppendingString:sender.titleLabel.text];
myDisplay.text = string;
}
I am new to IOS, Xcode and MVC. I am on a steep learning curve and am failing with what I assume is a most basic task.
I have a tabbed application with two tabs. Both tab views communicate with a web service and I want to add an image to each tab view, changing the image to indicate the connection state.
So, I created a third .xib file with a controller class (IconViewController). I am hoping to add and remove an instance of this icon view in each of the tab views.
Here is the pseudo code for my icon view:
#interface IconViewController : UIViewController
{
UIImageView *_icon;
}
#property (nonatomic) IBOutlet UIImageView *icon;
- (void)setForBusy;
- (void)setForOk;
- (void)setForFail;
And implementation:
#implementation IconViewController
#synthesize icon = _icon;
-(void)setForBusy
{
// Set Busy Icon Image
}
-(void)setForOk
{
// Set Ok Icon Image
}
-(void)setForFail
{
// Set Fail Icon Image
}
The icon IBOutlet is connected to an UIImageView on the accompanying xib file.
Here is one of the root tab controllers:
#import "IconViewController.h"
#interface TaboneViewController : UIViewController
{
IconViewController *_iconViewController;
}
#property (nonatomic) IBOutlet IconViewController *iconViewController;
and implementation:
#synthesize iconViewController = _iconViewController;
- (void)viewDidLoad
{
[super viewDidLoad];
self.iconViewController = [[IconViewController alloc]
initWithNibName:#"iconViewController"
bundle:nil];
[self.view addSubview:self.iconViewController.view];
}
In the tabView xib Interface Builder I added an Object and made it a class type IconViewController. I connected the Icon View Controller Object->Reference Outlet to the File Owner->iconViewController Outlet.
Running the project I get the error:
loaded the "iconViewController" nib but the view outlet was not set.
I have experimented with other connections but with no luck. It seems to me that my first connection should work but it doesn't.
Any idea what I am misunderstanding? Is the principle good (loading an instance of third view into two root views)? If so, what outlet needs connecting?
Many thanks, Polly
I see your issue. You want to have common stage of image for both tab. I think it is better to implement subclass of UIView (or UIImageView) and implement all methods like set (void)setForBusy and etc. The stage of image you should receive from parent ViewController, something like UINavigationView controller (if you have it). Otherwise you should save stage somewhere else. My personal opinion it is too expensive to create new controller just for your purpose.
Hope it helps.