i think there are two ways to add a UIControl in my view
status 1:
#property (nonatomic,weak) UIButton *button;
- (void)viewDidload
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button........ (set frame,color,text........)
[self.view addSubView:button];
_button = button;
}
status 2.
#property (nonatomic,strong) UIButton *button;
- (void)viewDidload
{
_button = [UIButton buttonWithType:UIButtonTypeCustom];
_button.......(set frame,color,text......)
[self.view addSubView:_button];
}
i want to know the difference between them and in different situation what should i chose ?
in version 1 (nonatomic, strong) the viewcontroller keeps a strong reference to the button. that means if you for example remove it from the superview somewhere in your code ([self.button removeFromSuperview];) it is still in memory and could be readded at a later point in time ([self.view addSubview:self.button];).
in version 2 (nonatomic, weak) the viewcontroller keeps a weak reference to the button. that means if you for example remove it from the superview somewhere in your code (and no other part of your app keeps a strong reference to it) it gets deallocated.
there is no real difference between creating a local variable UIButton *button = ... and assigning it to the instance variable afterwards _button = button; or working with the instance variable directly _button = [UIButton buttonWithType:....
in status 1:
you have marked you UIButton as weak Property
and A weak reference means the pointer has no owner, therefore it will be deallocated as soon as it is no longer needed (that is, nothing else is pointing to it).
but in status 2 :
you have marked you UIButton as Strong Property and when your Button hasn't mark as IBOutlet , you should use strong
Related
In view.h I declare
#property (retain, strong) UIButton *btn;
In view.m I first have:
#synthesize btn;
and then in implementation I have this call to a method in another class:
[self.view addSubview:[otherclass getTestBtn:btn]];
After this line, in my view.m, I try to log the text in the button like this:
NSLog(#"btn.titleLabel.text = %#", btn.titleLabel.text);
Unfortunately the logs says:
btn.titleLabel.text = (null)
In the other class.m I implemented the method this way:
btn = [[UIButton alloc] initWithFrame:CGRectMake(70, 340, 100, 25)];
[btn setTitle:#"HELLO" forState:UIControlStateNormal];
return btn;
In the simulator I see that the button shows the text "Hello". But from view.m the text in the button don't seem to be accessible. Why?
Im afraid that the button that is passed from view.m to other class.m is not passed by reference. And hence the button in view.m is not affected by the method in other class. Is that the reason? If yes: how to pass the button as reference? I tried with & character. But the editor shows errors.
If you want to get the button returned from the other class then you need to assign it to your property -
self.btn = [otherClass getTestBtn];
[self.view addSubView:self.btn];
Also, you should strong rather than retain as #dimimpou said and you don't need #synthesize any more unless you want to use a specific backing variable name.
In my project I used storyboard and when I accessed an UI element I created a property and linked it. This property is weak. To my understanding the property can be weak since it is already added to the view and the views retains it.
In an other project I do not use storyboard. Now I am not sure how to define a UI element. I think this can be done both, situation 1:
#interface LoginView
#property (strong, nonatomic) UIButton *login
#end
- (instancetype) init {
if (self == [super init]) {
_login = [UIButton buttonWithType:UIButtonTypeCustom];
[self addSubview:_login];
[self setNeedsUpdateConstraints];
}
return self;
}
Situation 2:
#interface LoginView
#property (weak, nonatomic) UIButton *login //<<notice weak
#end
- (instancetype) init {
if (self == [super init]) {
UIButton login = [UIButton buttonWithType:UIButtonTypeCustom];
[self addSubview:login];
_login = login
[self setNeedsUpdateConstraints];
}
return self;
}
My question is: "Can both situation be used? If so is there a preferred way?"
Own ideas: I think situation two is preferred since it doesn't create a second strong pointer?
Either will work fine.
Personally I prefer strong, so that I'm not relying on another view retaining something.
Also strong has slightly less overhead as opposed to a weak reference which needs to be tracked and zeroed to nil automatically (not that you would notice this time difference).
You can still use weak reference because the views super view will be having strong reference to it.
I have 2 classes
ClassA: UIView
ClassB: UIViewController
I have a UIButton in ClassA
The button is declared in the header and as an #property of A
UIButton *selectBtn;
}
#property (nonatomic, strong) UIButton *selectBtn;
in the .m file of Class A the button is initialized and shows up on screen
ClassB imports ClassA's header file and from it I'm trying to set the target and the action for my button with the following
[ClassA.selectBtn addTarget:self action:#selector(getSomething:) forControlEvents:UIControlEventTouchUpInside];
But i keep getting an Error message saying
"Property "selectBtn" not found on object of type "ClassA"
What am I doing wrong ?
any help or guidance is very appreciated
[ClassA.selectPicBtn addTarget:self action:#selector(getSomething:) forControlEvents:UIControlEventTouchUpInside];
use selectPIcBtn instead of selectBtn
I don't know if I'm missing something because none of the other posters brought this up but from what I see selectBtn is a property of a ClassA instance, not a property of the class itself. Try grabbing an instance of a ClassA object and then accessing the property from that instance:
//WRONG
[ClassA.selectBtn addTarget:self action:#selector(getSomething:) forControlEvents:UIControlEventTouchUpInside];
//Correct
ClassA *aClassAObject = [[ClassA alloc] init];
[aClassAObject.selectBtn addTarget:self action:#selector(getSomething:) forControlEvents:UIControlEventTouchUpInside];
Please keep in mind, the above code is just an example and is not likely the object you are looking for. If you are doing this inside the ClassB object you have to grab the ClassA UIView that is actively being used by the ClassB UIViewController. Typically, I would create a property in ClassB to access the ClassA object similar to the way you created a property for a UIButton object but I'm not sure how you have your classes setup without seeing the header files.
Problem is here.
UIButton *selectBtn;
}
#property (nonatomic, strong) UIButton *selectPicBtn;
selectBtn and selectPicBtn are different. property name should be same as variable name. If you have declared a property then you don't need variable declaration.
Only declare property and use it. While initializing, initialize self.selectPicBtn = [UIButton.... in Class A
As said in the title, my IBOutletCollection of UIButtons is empty after viewDidLoad.
I created a IBOutletCollection of UILabels the same way, and this one is working perfectly.
Any idea how this can be fixed, or where i made a mistake?
Here is the Code:
#property (strong, nonatomic) IBOutletCollection(UILabel) NSArray *lbl_save;
#property (strong, nonatomic) IBOutletCollection(UILabel) NSArray *lbl_cancel;
#property (strong, nonatomic) IBOutletCollection(UILabel) NSArray *lbl_edit;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *btn_changeData;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *btn_save;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *btn_cancel;
The buttons are placed in a xib and linked correctly to the corresponding outlets. Just like the labels.
The time i press the one of the Buttons is the first time, i want to access the Buttons in Code.
for (UIButton *btn in _btn_changeData) {
btn.hidden = NO;
btn.userInteractionEnabled = YES;
}
for (UIButton *btn in _btn_save) {
btn.hidden = YES;
btn.userInteractionEnabled = NO;
}
for (UIButton *btn in _btn_cancel) {
btn.hidden = YES;
btn.userInteractionEnabled = NO;
}
for (UILabel *lbl in _lbl_save) {
lbl.hidden = YES;
}
for (UILabel *lbl in _lbl_cancel) {
lbl.hidden = YES;
}
for (UILabel *lbl in _lbl_edit) {
lbl.hidden = NO;
}
That is also where i got the following Exception and realized, that my Button OUtletcollection is empty.
-[UIButton countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0xa8a8850
I neither overwrite the outletcollection, nor do i change attributes of the buttons.
Its just that the labels are there in the collection and the buttons not. And i have no idea why.
Thx in advance for any help.
Mav
First idea that comes to my mind is that the properties are not correctly synthesized. Is _btn_changeData really the ivar behind btn_changeData property?
Second idea is something I saw while debugging someone else's code. When outlets are incorrectly connected, for example, if the controller references itself, two controller instances can be create. Obviously only of of them will have the outlets connected. Make sure only of instance is created.
For debugging, implementing the setter by yourself might be a good idea.
Edit:
After rereading, the problem is actually different they you say in your question. The error message -[UIButton countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0xa8a8850
doesn't mean that _btn_changeData is an empty array. It means there is a UIButton instead of an array.
Having said this, you should check if you are not overwriting the data in _btn_changeData somewhere.
I was digging around on SO and thought I had figured out how to do this but my test failed. I'm trying to close a popovercontroller from the viewcontroller that is launched/contained (I'm still a bit fuzzy on the poc and vc relationship) by it.
In my viewcontroller .h I have this:
#interface OAI_vcOperatingRooms : UIViewController {
OAI_ColorManager* colorManager;
OAI_FileManager* fileManager;
UIPopoverController* myPopOverController;
}
#property (nonatomic, weak) UIPopoverController* myPopOverController;
- (void) closeVC : (id) sender;
and in the .m file
UIButton* btnClose = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnClose addTarget:self
action:#selector(closeVC:)
forControlEvents:UIControlEventTouchDown];
[btnClose setTitle:#"Close" forState:UIControlStateNormal];
btnClose.frame = CGRectMake(10.0, 210.0, 160.0, 40.0);
[self.view addSubview:btnClose];
- (void) closeVC : (id) sender {
[myPopOverController dismissPopoverAnimated:YES];
}
in the uiview that calls the popovercontroller, I've referenced the viewcontroller and added this:
//operating rooms
controller2 = [[OAI_vcOperatingRooms alloc] initWithNibName:#"OAI_vcOperatingRooms" bundle:nil];
popoverController2 = [[UIPopoverController alloc] initWithContentViewController:controller2];
controller2.myPopOverController = popoverController2;
No errors but nothing happens when I hit the close button. Is it possible to reference a POC from within the VC?
Thanks
I believe ott’s comment is on to something - try using a strong property instead of a weak one. A weak property is likely to get set to nil by ARC immediately after its last use. A strong property will stick around for the lifetime of its parent object (in this case, your UIViewController subclass), unless you set it to nil early.
Note: you probably don’t need UIPopoverController *myPopOverController; in your interface, since Xcode will automatically generate _myPopOverController as a backing variable.