I have been playing a bit with the memory in order to be a good memory citizen on the iPhone SDK.
However I still struggle to understand the difference between "self.something" and just "something".
As far as I understood, "self.something" means ask to the class for "something", but there is something wrong on my thought. Let's see the example:
I have worked with the memory releasing:
[self.labelIBOUtlet release] -> It crash
[labelIBOUtlet release] -> It doesn't.
Can anyone please explain me what is the reason?
Thank you!
EDIT:
This is the information I have set on the header file:
#interface viewController : UIViewController {
UILabel * labelIBOutlet ;
}
#property (nonatomic,retain) IBOutlet UILabel * labelIBOutlet ;
You have to understand the meaning of "property"
the use of "dot" is just a faster way to call "special methods" created just to "set" and "get" variable-property.
as example, you could have your own class/UIView which uses a subView:
in myView.h
#interface myView : UIView {
UIWebView *webView;
}
if you do just this you have not a "property", but just an ojbect...
so in your myView.m you try to use the "dot" like this:
NSLog(#"%i", self.webView.frame.size.width);
then you get an error, you cannot do that, xCode says:
error: accessing unknown 'webView' getter method
that just means that a the method "webView" doesn't exist...
'couse when you call "self.webView" you just call a method called "webView"...
this method just return the pointer to your value.
and when you call:
self.webView=someValue;
you are just calling the method "setWebView", a method that just set your object with someValue...
but so... where do those 2 invisible methods come from?
they are created by xCode itself if you tell it to use webView as a property...
in our example, add some lines:
in myView.h
#interface myView : UIView {
UIWebView *webView;
}
#property (nonatomic, retain) UIWebView *webView;
in myView.m
#implementation myView
#synthesize webView;
// ...
doing this xCode will add the 2 methods "webView" and "setWebView" for you,
and now you can call:
NSLog(#"%i", self.webView.frame.size.width);
with no error...
and you can put value (of the right format, in this case a pointer to an existing UIWebView)
just calling:
self.webView = aUIWebView;
and remember to release it, 'couse you used "retain" in :
#property (nonatomic, retain) UIWebView *webView;
release it with:
[webView release];
Did you #synthesize labelIBOutlet in the implementation file?
If you do not have labelIBOUtlet in your object declared it will fall on calling self.labelIBOUtlet because it do not exist.
self == is in the object which is declared in header file
hope it makes it clear
Related
I'm working on a project in objective C where i have to modificate some variables which are in a view controller from uiviews.
So i've tried somethings like this :
ViewController.h :
#property (nonatomic) bool Contact;
One of the UIViews :
ViewController * View;
View.Contact = YES;
I've also tried to make a setter method like this in the ViewController :
-(void) SetterContact:(bool)boolean;
And so to modificate from a UIView like this :
[View SetterContact:YES];
But it's looking working.
I've read that i have to init the object in which is containt the variable, but in memory management it's not really good to make some initializations from object who are already actives no ?
So if View is already init, i'm not going to call the init method from another UIView no ?
Thanks for your help !
If you want bool variable to be accessible from other viewController.Then simply wirte it as :-
#property BOOL Contact;
and make an object of ViewController in which you have declared contact variable as BOOL and access this variable using like this:-
OtherViewController *otherViewController=[[OtherViewController alloc] init];
otherViewController.Contact=YES;
As it is a instance variable it has to be accessed using class object.
use #property (nonatomic, assign, getter = isContact) BOOL contact; in your .h file.
Respect naming conventions
#property (nonatomic,retain) UIViewController *myController;
don't forget to synthesize
#synthesize myController = _myController;
If you want to implement your own setter do this: respect the naming convention
-(void)setMyController:(UIViewController*)controller;
or if by any bizarre reason you can't respect naming convention you can point the property to the method you want
#property (nonatomic,retain,setter=myBizarreSetterMethod:) UIViewController *myController;
this can help you out as well question in stackoverflow
Super class Resource
#interface Resource : CoderObject
#property (strong, nonatomic) NSString *resourceID;
#property (assign, nonatomic) ResourceType resourceType;
#property (assign, nonatomic) DataType dataType;
#end
Subclass ViewResource
#interface ViewResource : Resource
#property (strong, nonatomic) CustomView *view;
#property (strong, nonatomic) UIViewController *viewController;
#end
In subclass ViewResource's init method how to access Resource's variable dataType? Now I'm trying to just use super.dataType = ...
Is there other ways?
You just need to use self.dataType. Your subclass has full visibility of all of the superclass properties defined in the .h file. Using self.xxx also gives you the ability to override the accessor methods if required in the future without coming back to edit all of your usage code.
Looking at your link below, fair enough. Those are all valid points. Accessors shouldn't have side effects but you can't guarantee they won't. If the property is defined the superclass then you have a couple of options:
Use self.xxx to set the property and endeavour to ensure no side effects
Call an init method on super, passing the required parameters, and set them there
Like Wain stated in his answer you have direct access to your super's class members (if they are not private).
And there is no problem calling self.property in the init method as long as your init looks like this
-(id)initAndTheNameYoWantAndMaybeSomeParameters:(NSString *)paramExample {
self = [super initNameOfAnInitMethodFromSuperClass];
//check if the init was with success
if(self != nil) {
self.myStringProp = paramExample;
//or
self.propertyFromSuper = paramExample;
}
}
Yes, you can also do stupid stuff in the initMethods (I did it before :)) ) like calling the same initMethod from inside it which was generating a recursive calling that was crashing my app. (Easy to spot this issue)
I have 2 classes geoViewController and geoMainViewController
I have a method in the geoMainViewController called getFoo
It looks like this:
- (NSString *)getFoo
{
NSString* foo = #"This is foo";
return foo;
}
I am trying to call getFoo from the geoViewController class.
I have #import "geoMainViewController.h" in my geoViewController m file.
I am trying instantiate the geoMainViewController class and call the getFoo method from the viewDidLoad in my geoViewController class like this:
- (void)viewDidLoad
{
[super viewDidLoad];
geoMainViewController* mainVC = [[geoMainViewController alloc] init];
NSString* myFoo = [mainVC getFoo];
}
It seems to be instantiating the geoMainViewController class fine but I am getting an error on NSString* myFoo = [mainVC getFoo];
The error is - no visible #interface for 'geoMainViewController' declares the selector 'getFoo'
I am sure I am missing a step because I am very new to Objective C. I am just not sure what I am doing wrong.
Any help on this would be great.
Thanks!
In your geoMainViewController.h you should declare the selector to be visible:
-(NSString *)getFoo;
Did you put - (NSString *)getFoo in your geoMainViewController.h ?
You have to make those methods visible to the outside of your object through the .h file, so other objects know which selectors they respond to. Did the autoComplete fill in the message per chance?
#import <Foundation/Foundation.h>
#interface
{
}
#property (nonatomic,strong) ;
#property (nonatomic,strong) ;
#property (nonatomic, strong) ;
- (NSString *)getFoo
#end
EDIT: (You could also just make Foo a property by the way)
Did you declare it in your header file?
Header file contains all the function declarations in the .h file and you only include the .h file in your class. So it depends on .h file. .h file will have all the functions as the .m file.
Hope it helps you.
You are misunderstanding how to use a view controller. While you can technically create an instance of a view controller in order to call one of its methods, you shouldn't do so. The normal approach is that the view controller is part of the view hierarchy and you can call methods on it when you have access to that instance. You are missing something fundamental here.
Your actual error is a missinh method declaration, I would suspect, but you have bigger problems to solve first.
I am having a label code for "decisionText" inside dot-m file as follows :
#synthesize decisionText ; //<<<This generates the error
inside dot-h file, the code is written as follows:
IBOutlet UILabel *decisionText
The error i get is :
No declaration of property 'decisionText found in the interface.
ps: In the interface builder when i click the label, i can find the name "decisionText" under Referencing Outlets mapped with File's Owner
Stuck on this. :(
As suggested I removed line #synthsize decisionText and used :
#property (nonatomic,weak) IBOutlet UILabel *decisionText ;
Now i get the error :
Expected a property attribute before 'weak'
Dot M file :
#import "ClickButtonViewController.h"
#implementation ClickButtonViewController;
//#synthesize decisionText ;
#property (weak,nonatomic) IBOutlet UILabel *decisionText ;
-(IBAction)buttonPressed:(id)sender
{
decisionText.text = #"Go for it!" ;
}
-(void)dealloc{
[decisionText release];
[super dealloc] ;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
#end
in the .h file add:
#interface ViewController : UIViewController
{
//....
IBOutlet UILabel *decisionText ;
//...
}
#property (nonatomic, retain) IBOutlet UILabel *decisionText ;
//...
#end
then in the .m file add:
#synthesize decisionText ;
You use #synthesize statements with declared properties. Thus, your code should probably look like:
#interface ViewController : UIViewController
{
// your ivars go here
// but this is not needed:
//
// IBOutlet UILabel *decisionText;
}
// your properties go here
#property (nonatomic, retain) IBOutlet UILabel *decisionText;
#end
If you're using ARC, replace retain with weak.
And in your .m file, you would have:
#implementation ViewController
#synthesize decisionText = _decisionText;
// and your implementation goes here
Note:
While you can explicitly declare your instance variable, if you omit it, the #synthesize statement will create one for you. Thus, you don't need to explicitly declare any instance variable. In fact, I might argue that you should not explicitly declare your instance variable because if you have a typo, it only presents an opportunity to accidentally end up with two instance variables, the one you explicitly declared and the one the compiler will generate. I've seen that problem here on Stack Overflow more than once. So, in my example, I've omitted the explicit instance variable declaration and I'll let the compiler take care of it for me and it minimizes the chance for error.
While not required, it is often advised that #synthesize statements specify a different name for your property's instance variable (e.g., in this case, I'm suggesting that the property decisionText would have an instance variable of _decisionText). This helps discourage the accidentally reference to instance variables when you meant to invoke the property's getter or setter. (In fact, in Xcode 4.4 and later, if you omit the #synthesize statement, the compiler will automatically synthesize the instance variable for you with the leading underscore.) Thus, in your code, you would then refer to the property self.decisionText or to the instance variable _decisionText. It's generally not so critical for IBOutlet objects, but as you start to use your own custom properties, this convention becomes useful.
Alternatively, if you are using Xcode 4.4 you can use autosynthesis.
In which case you don't need to declare the iVar you can just write:
#property (weak, nonatomic) IBOutlet UILabel *decisionText;
And you don't need to write the #sythesize line at all.
If you do this - be aware that the generared iVar will have a leading underscore appended by default, although you should just stick to using the property accessor in this case so it makes little difference.
You can see what you can do in the Objective-C Features Availability Index
Change
IBOutlet UILabel *decisionText
to
#property (nonatomic, weak) IBOutlet UILabel *decisionText
You can only synthesize properties you defined like that with the #property keyword
You declared only the instance variable which will store the content of your property but you didn't declare the property itself. I think that the easiest way to solve that is to add in your public interface (.h file) or in your private interface (#interface ClassName () ... #end in ClassName.m file) the declaration of the property.
ClassName.h
#interface ClassName : ParentClass
#property (nonatomic, weak) IBOutlet UILabel decisionText; //This is the declaration of the property than you can ctrl-drag to wire it up to your label
#end
ClassName.m
#implementation ClassName
#synthesize decisionText = _decisionText //the _decisionText stuff is the name of the instance variable that will store the content of your property
... //your methods
#end
I need to get things clear about Objective-C memory management:
If I declare an object in the class header as ivar without #property:
#interface MyFacebooDelegate : UIViewController
{
TableViewController *tableController;
}
...
#end
and some where in the code for example in - (void)viewDidLoad I do :
tableController = [[TableViewController alloc] init];
so where is best way to release it. What if I make the instant object a property what will be the different? and how the memory management will be too
#interface MyFacebooDelegate : UIViewController
{
TableViewController *tableController;
}
...
#end
#property (nonatomic, strong) TableViewController *tableController;
What the following syntax do exactly for the object viewController:
.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) ViewController *viewController;
#end
.m
#implementation AppDelegate
#synthesize window = _window;
#synthesize viewController = _viewController;
- (void)dealloc
{
[_window release];
[_viewController release];
[super dealloc];
}
.....
#end
If I want to return an object through a method to another class, do I need to autorelease it in the method body first and then retain it in receiver side?
for example this method what exactly to do in the method body and in the receiver side too:
-(NSString *)getFriendId
{
NSArray *ar = [NSArray arrayWithObjects:#"1",#"2",#"3", nil];
return [ar objectAtIndex:0];
}
I know this a lot but I am really confused and need your help.
1) best way is in dealloc; or right before re-setting it.
2) a property does the retain/release for you. But WARNING! You keep mixing up things. You use "strong" here, which relates to ARC. If you really insist on using classic retain/release (you shouldn't) then use (nonatomic, retain) instead.
3) Your properties get deallocated on dealloc. Again, strong is wrong here.
4) Yes. Ideally you should. Another reason why ARC is awesome, it does this all for you, automatically.
tl;dr: Use ARC. Never go back. (But still learn manual memory management)
ARC is the answer for your all memory management question. Very import note on Strong and Weak property in addition to ,
iOS Strong property: So strong is the same as retain in a property declaration before ARC. For ARC projects I would use strong instead of retain, I would use assign for C primitive properties.
iOS outlets should be defined as declared properties. Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create will therefore typically be weak by default, because: Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, are arbitrary references between objects that do not imply ownership.