I've set a switch on my overlay, which appears every time my app launches the camera. The switch appears, which is fine. But how do I create the if conditions to command the switch to perform an action when on or off?
//This is the overlay.
- (UIView*)CommomOverlay {
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake (30,400,20,20)];
[mySwitch addTarget:self action:#selector(mySwitch)
forControlEvents:UIControlEventAllTouchEvents];
[view addSubview:mySwitch];
return view;
}
So the switch appears on the overlay, but how do I command it do something when called?
I've tried the following
-(void)mySwitch {
if ([mySwitch.on]){
execute this..
}
}
But the above doesn't work. I get an error saying "undeclared identifier, did you mean UISwitch?". So then I replace mySwitch.on with UISwitch.on, then it says " property on not found on object of type UISwitch".
I just want to execute my if else method properly. I made the overlay, I made the switch code and it appears on the overly perfectly. But now I want it to do something with an if/else condition. How do I rectify this?
What did I do wrong?
Glad you decided on the UISwitch, its a much more straightforward solution in my opinion. As for what your problem is, its related to scoping. You are declaring your UISwitch in your overlay initialization, and then the function ends, and you lose the ability to access your UISwitch.
What you'll need to do is create a property for it in your .h, then just set it equal to your property inside of your overlay initialization. That should fix your problem.
EDIT: Going through the problems you mentioned in the comment:
1) I believe that your declartion should be,
#property (nonatomic, retain) UISwitch *mySwitch;
Afterwards, you will need to do a #synthesize mySwitch; in your .m file
2) The reason for this is because you have 2 variables with the same name since it seems that you are redeclaring mySwitch in a few places. I'm guessing these places your code looks like:
UISwitch *mySwitch = //Stuff;
It should just look like:
mySwitch = //Stuff;
The reason being that you have already declared it in your .h file, you simply need to initialize or manipulate it. If you declare it once again, you will be overwriting it with a new instance that will once again not exist after you exit your function.
3) You dont need to set mySwitch = mySwitch for the synthesize, see my above code. Also make sure that your function name is not the same as your variable name!
Feel free to comment with updates and more questions.
-Karoly
mySwitch is not accessible in your mySwitch method. Create a property for mySwitch and create it's getter and setter. Then you can access it in your mySwitch method.
[..]
#property UISwitch *mySwitch;
[..]
#synthesize mySwitch = mySwitch;
-(void)mySwitch {
if ([self.mySwitch.on]){
[..]
}
}
Related
I have two scenes that I made in SpriteBuilder, one is Shop and the other is UpgradesNew. Shop is a CCNode layer and UpgradesNew is a CCNode layer. I have two CCScrollViews in the MainScene that load Shop and UpgradesNew respectively.
When one button in Shop is tapped, the label in UpgradesNew should change colors. I have been trying to implement this using delegates but it's not working.
Here's what I did...
In shop.h I set the protocol:
#protocol changeColorProtocol <NSObject>
#required
-(void)changeColor;
#end
Then I set the id
#property (nonatomic, retain) id <changeColorProtocol> delegate;
Here is the button that when clicked, should use changeColor. This is in shop.m
-(void) buyDiggerShibe {
[self.delegate changeColor];
[self didLoadFromCCB];
}
Now in UpgradesNew.h I made it adopt the protocol like this
#interface UpgradesNew : CCNode <changeColorProtocol>
And in UpgradesNew.m
I set delegate to self in ViewDidLoad.
Shop *shop = [[Shop alloc]init];
shop.delegate = self;
.
-(void)changeColor {
if (hasDigger == YES) {
shovelRequires.color = [CCColor greenColor];
NSLog(#"HEY HEY HEY");
}
}
I probably have parts of the delegate placed in the wrong area because I was trying to switch them around when it wasn't working, I'm not sure where they are supposed to go. I've watched multiple delegate tutorials and it just seems overly complicated, at least with what I am trying to do.
Any ideas?
EDIT:
Tried this.
I created a property in UpgradesNew
#property (strong, nonatomic) Shop *shop;
Then I synthesized it in the implementation and allocated it like this in didLoadFromCCB, instead of creating a new object:
self.shop = [[Shop alloc]init];
shop.delegate = self;
EDIT: This is how I am creating objects.
Drag a label into a layer. Identify it then define it in header as CCLabelTTF *label; That's it, thats all I do to create any object on the layer.
To create a layer like Shop or UpgradesNew, I hit New -> File -> Layer. That creates a new CCNode. Then I set the class of the CCNode, as shown in the picture the CCNode that is highlighted has a class of MainScene. If I want to establish a #property to that CCNode I just type the name in the box right below custom class and set it as doc root var, and then put it in the header as CCNode *MainScene. I don't do anything other than that.
I don't know anything about SpriteBuilder, so it's a bit hard to address your question. You might want to add SpriteBuilder to the title of your post so people who use that framework are likely to read it.
You need to explain how the 2 "CCNode layer"s are created, and how you link them together. In order for one object to have another object as a delegate, the delegate property has to be set somewhere. Where is that setup being done? Have you set a breakpoint at the line
[self.delegate changeColor];
To make sure that self.delegate is not nil?
Have you set a breakpoint in your changeColor method, or added a log statement, to see if it's being called? My guess is that self.delegate is nil, so the messages is being dropped on the floor (it's legal to send messages to nil in Objective-C. It just doesn't do anything.)
okay below is a standard example of creating a datepicker
- (void)viewDidLoad {
CGRect pickerFrame = CGRectMake(0,250,100,100);
UIDatePicker *myPicker = [[UIDatePicker alloc] initWithFrame:pickerFrame];
[myPicker addTarget:self action:#selector(pickerChanged:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:myPicker];
[myPicker release];
}
- (void)pickerChanged:(id)sender
{
NSLog(#"value: %#",[sender date]);
}
this is all good and well. I'm a little used to creating elements in IB so when I create an object programatically I'm not sure how to access the data.
What I mean is.. should I assign myPicker to a class property and then access it as _myPicker?
Or lets say I want to access the date inside of the pickerChanged method without calling another method. Should I assign an NSDate property and re-assign it every time the picker is changed?
I ran into some memory issues when I was trying to do it that way. I had another method grabbing _theDate, and it probably tried to access it at the same time pickerChanged was modifying it?
Anyway, what I'm getting at is "whats the proper workflow when creating things like action sheets, and pickers programmatically". When these things are changed, how should the resulting data be saved so the rest of the class can access it?
Bonus question:
Is there a difference between this?
for(UILabel *myLabel in view.subviews){
NSLog(myLabel.text);
}
and this? Do I need to check the class all the time if i know my view only contains a certain kind of object?
for((id) myLabel in view.subviews){
if([myLabel isKindOfClass:[UILabel class]){
UILabel *theLabel = myLabel;
NSLog(myLabel.text);
}
}
Generally, you will just define properties if you'll need to access them more than once. You can do this in the .m file's interface:
#interface MyObject()
#property (weak, nonatomic) UIDatePicker *myPicker;
#end
You will then be able to access it by either _myPicker or self.myPicker.
You shouldn't need another NSDate property in your class because you can access the set date at any time:
_myPicker.date
For your last question: the latter of the two is merely extra sanity checks. While you're writing your own code, and you should know what subviews you're adding in, it can't hurt to double check the type of the subviews incase anything should go wrong and you try to access selectors that don't exist. This is a larger programming question though and not necessarily objective-c or iOS specific.
The documented approach is to intercept the UIControlEventValueChanged event, as per your example.
You would then typically copy the [sender date] value to a property in your pickerChanged: method.
If the user hits a save button, then the object that presented the view containing the picker should be able to retrieve the selected date via the property.
It's not considered good practice to use isKindOfClass:. You should structure your code such that you always know what class you're dealing with.
Also, you should really switch to ARC so you don't need to worry about calling release
You need to declare a UIDatePicker property to hold one instance of your child controller
This is what you need to add in your .h file:
#property (strong, nonatomic) UIDatePicker *myPicker;
And then in your .m file you need to add a data source method for this date picker. something like what rdelmar has instructed above:
self.myPicker = [[UIDatePicker alloc] init];
Im trying to make it so that every single UIControl in my application (UIButton, UISlider, etc) all have special extra properties that I add to them.
I tried to accomplish this by creating a UIControl Category and importing it where needed but I have issues.
Here is my code.
My setSpecialproperty method gets called but it seems to be getting called in an infinite loop until the app crashes.
Can you tell me what Im doing wrong or suggest a smarter way to add a property to all of my UIControls?
#interface UIControl (MyControl)
{
}
#property(nonatomic,strong) MySpecialProperty *specialproperty;
-(void)setSpecialproperty:(MySpecialProperty*)param;
#end
////////
#import "UIControl+MyControl.h"
#implementation UIControl (MyControl)
-(void)setSpecialproperty:(MySpecialProperty*)param
{
self.specialproperty=param;
}
///////////////
#import "UIControl+MyControl.h"
#implementation ViewController
UIButton *abutton=[UIButton buttonWithType:UIButtonTypeCustom];
MySpecialProperty *prop=[MySpecialProperty alloc]init];
[abutton setSpecialproperty:prop];
While you can't add an iVar to UIControl via a category, you can add Associated Objects, which can be used to perform much the same function.
So, create a category on UIControl like this:
static char kControlNameKey;
- (void) setControlName: (NSString *) name
{
objc_setAssociatedObject(self, &kControlNameKey, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *) controlName
{
return (NSString *)objc_getAssociatedObject(array, &kControlNameKey);
}
There's more to it than that, I guess you'll need to check if an association exists before setting a new one, otherwise it will leak, but this should give you a start.
See the Apple Docs for more details
self.specialproperty=param is exactly the same as calling [self setSpecialproperty] (see here for some totally non biased coverage of Obj-C dot notation), which makes your current usage infinitely recursive.
What you actually want to do is:
-(void)setSpecialproperty:(MySpecialProperty*)param
{
_specialproperty = param;
}
Where _specialproperty is the implicitly created ivar for your property.
I'm assuming there's some reason why you've implemented your setSpecialproperty setter? Why not just use the one that is implicitly created for you?
the problem is that you can not add a property to a category, you can add behavior (methods) but not properties or attributes, this can only be done to extensions, and you can not create extensions of the SDK classes
use your method as
change your method name to
-(void)setSpecialproperty:(MySpecialProperty *)specialproperty
-(void)setSpecialproperty:(MySpecialProperty*)specialproperty
{
if(_specialproperty!=specialproperty)
_specialproperty = specialproperty;
}
and synthesize your specialProperty as
#synthesize specialproperty=_specialproperty;
I have the following code:
#interface MyCell : UITableViewCell<UITextFieldDelegate>
{
IBOutlet UITextField *txtFields;
}
- (IBAction)textFieldAction:(id)sender;
#property (nonatomic,retain) IBOutlet UITextField *txtFields;
#end
I also have the following delegate function:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
return NO;
}
However, I notice that it's NEVER being called. I set the delegate from the interface builder as well as from code as per: [txtFields setDelegate:self]; but neither seems to work. Is there something else i'm missing for this?
You are obviously using this in conjunction with a UITableView. First, if you want to support user interaction, the txtFields must be a subview of the cell's contentView, not the backgroundView.
Assuming that the txtFields object is a subview of the contentView, then lets look at the connections.
The tableView has a a method cellForRowAtIndexPath: where you either return a new cell or a recycled cell. At the very bottom of that cell, add:
NSLog(#"textFields=%# delegate=%#", cell.txtFields, cell.txtFields.delegate);
assert(cell.txtFields.delegate == cell); // lets make sure this is proper
If in fact both arguments are there, you now know that the txtFields object is in the proper container (contentView), that the property is working, and that the delegate is set to the cell.
If that is all proper and you do not get the keyboard when you tap, then most likely something else is overlaying the txtFields - some other transparent view and its eating the touches.
In that case you should throw together a little demo app using the MyCell class, with even just one hardcoded cell, that demonstrates the problem, then upload that (zipped) to your DropBox account where others like myself can take a look at it and find the problem.
Try removing:
{
IBOutlet UITextField *txtFields;
}
since you have a #property already.
Also, did you #synthesize txtFields;?
I just witnessed a very strange issue where my view would ignore all of the delegate calls coming from a custom view because I called alloc/init on the item at the load. I'm curious as to why.
#synthesize customTextField;
-(void)viewDidLoad {
// by calling this alloc/init, none of the changes here actually update to the view
// everything is ignored from here on in.
// if I comment out the alloc/init line, everything works fine
self.customTextField = [[UITextField alloc] init];
self.customTextField.text = #"Some text";
// setting font and size as well
}
While I would still get calls to the text field delegate methods, none were linked to my specific text fields. I could not respond to just customTextField.
I do realize that calling alloc/init will give me a completely new instance of customTextField... but why wouldn't that new instance be linked to IB and my view?
Because IB linking != binding.
When you link a variable in IB, it's a simply sets the variable once on first load, that's it. It does no other special code to track any changes to it, for good reason.
For example:
You are designing a UITableViewCell, and if you have a cell that is selected, you must rearrange all of the content inside the cell. In this case, you determined it would be easier if you just recreated all of the subviews and re-added them into the view, so you do the following:
-(void) layoutSubviews {
if (cellIsSelected)
{
// custom button is an IBOutlet property, which is by default a subview of self
self.customButton = [UIButton buttonWithType:UIButtonTypeCustom];
[[self someSubView] addSubview:customButton];
}
else {
// where is customButton located now? is it a subview of self or `someSubView`?
self.customButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
// [self addSubview:customButton];
}
}
Thus, it is much easier for IB to say let's set this once, and let the programmer figure the rest out than for IB to try and track all changes made to an object and report them the to the UI.
viewDidLoad is called after your nib is loaded, and creating a new UITextField instance at this point will not be associated with your nib. If you're setting up new instances manually you also need to manually setup the delegates, and add them as subviews of your view.
The XIB file has no way of knowing that you are changing the reference. Consider the following piece of code
NSObject *myObjA = [[NSObject alloc]init]; //create object
NSObject *myObjB = myObjA; //assign reference <- this is the your case after xib load
myObjB = [[NSObject alloc]init]; //create object, myObjA still lives on.
It's basically the same that happens when you load your XIB file; You get the reference to the instantiated object (equals myObjB in above example). You can do with the reference what ever you please but you do not change the interface instance just by creating a new object.