I am trying to access an instance of SVSegmentedControl
It's a subclass of UIControl.
I created that instance during viewDidLoad
SVSegmentedControl *mySC = [[SVSegmentedControl alloc] initWithSectionTitles:[NSArray arrayWithObjects:#"Normal", #"Limosine", #"Any", nil]];
It does have a method - (void)segmentedControlChangedValue:(SVSegmentedControl*)segmentedControl { which I will be able to access the instance when the value is changed. But how do I access the instance(mySC) at other parts of the code?
Set a property in your UIViewController, and instead of creating a new instance variable, set the property to the newly initialised segmented controller. And from there on you can access it outside the viewDidLoad's scope.
Edit...
You really need to learn how to propertize / setter & getter a variable rather than asking people to post code for you.
Below the } in the header file:
#property (nonatomic, retain) SVSegmentedControl *control;
Top of the implementation file
#synthesize control;
To set it:
self.control = [[[SVSegmentedControl alloc] init...] autorelease];
It should be set to nil in the dealloc method.
Related
Here's a pseudo class to demonstrate:
myView : UIView
- (void) init {
UIScrollView * scroller = [[UIScrollView alloc] init];
scroller.delegate = self;
[myView addSubview:scroller];
return self;
}
Under ARC, do I need to do anything else for memory to be freed correctly when all other references to myView have been removed? Will the reference between the two objects keep them sticking around forever without any intervention?
Does this change depending on whether or not scroller is a class property, or just a local variable declared in the function?
Just trying to find out why I've got multiple instances of some classes sticking around that shouldn't be there - semi related question, is there an easy way to find out why an object stays in memory (eg see all references to this object)?
iOS classes (like UIScrollView and UIWebView) already handle this correctly.
However, if you have your own delegate protocols and delegate properties, you need to make sure they are set to assign and not retain. To do this, wherever you declare a delegate (or whatever kind of protocol) you need to add the __unsafe_unretained tag thing:
#protocol FooBarDelegate {
//...
}
#interface Foo : Bar {
__unsafe_unretained id <FooBarDelegate> delegate;
}
#property (nonatomic, assign) id <FooBarDelegate> delegate;
Does this change depending on whether or not scroller is a class
property, or just a local variable declared in the function?
It doesn't. However keep in mind that adding something as a subview, the parent view will retain it automatically, regardless if you have a property or not.
Specific performance and behaviour difference using properties or accessing the ivars directly.
For Global variables, What is the difference between using this:
#interface myClass (){
UIImageView *myView;
}
-(void)loadView{
[super loadView];
myView = [[UIImageView alloc] initWithFrame:CGrectMake(0,0,100,100)];
}
And doing this:
#interface myClass (){
}
#property (nonatomic, strong) UIImageView *myView;
#synthesize myView = _myView;
-(void)loadView{
[super loadView];
myView = [[UIImageView alloc] initWithFrame:CGrectMake(0,0,100,100)];
}
What benefits can we have with every approach?
What are the reasons to recommend to always uses properties?
In the first case, your instance variable (or ivar) myView is private to the class and cannot be accessed by another class.
In the second case, you have provided a property that allows other classes to access your ivar via synthesized accessors. The alternative to declared properties is to write your own accessor methods. The #synthesize notation does that for you.
See Apple documentation on declared properties
ALWAYS create a #property for every data member and use self.name to access it throughout your class implementation.
NEVER access your own data members directly.
Here are some of the reasons to use Properties:
Properties enforce access restrictions (such as readonly)
Properties enforce memory management policy (retain, assign)
Properties are (rarely) used as part of a thread safety strategy (atomic)
Properties provide the opportunity to transparently implement custom setters and getters.
Having a single way to access instance variables increases code readability.
You can also check out: The Code Commandments: Best Practices for Objective-C Coding
Synthesize makes you getter and setter methods which are called automatically depending on whether you try read or write the value. For the myView property:
myView = newView1; // using direct ivar access
myobject.myView = newvew1; // eq [myobject setMyView:newvew1]; where setMyView: is generated for you automatically with respect to assign/retain, the same for reading:
newvew1 = myobject.myView; // newvew1 = [myobject myView:newvew1];
the generated getter/setter names are customizable with setter=/getter=, if you don't need setter use readonly.
There's no way you can forbid other classes to use synthesized getter and setter, the ivars are #protected by default and if you want to provide other classes an access to the ivars, you can declare them under #public:
#interface myClass (){
UIImageView *myView; // this is protected
#public
UIImageView *myPublicView; // this is public
}
In your first example you access your ivar directly and changing its content. In your second example (the property) an ivar has been created automatically to back the property and all your calls to set and get the property are sent as messages (like: [self setMyView:[[UIImageView alloc] initWithFrame:CGrectMake(0,0,100,100)]];). The accessor methods are also created automatically. This means that you are now following KVC/KVO protocols. For more on the benefits of this design see here
I know how to retrieve variables from your parent view...
which is by doing something like this
[(mainViewController *)[self.superview] variableName];
but now i would like to know how to send variable data to a subview...
specially if i do something like this
ScreenTwoViewController *screen2 = [[ScreenTwoViewController alloc] init];
...
...
[self.addSubview:screen2.view];
in screenTwo i have a variable name Message:
I would like to send a variable message to the actual view so it can display the message in that view based on what the parent view sends it when adding the screen2 view as a subview??
Well if you have set the property for the variables in the subview like this.
#property (nonatomic, retain) NSString *message;
and also synthesis it in your .m file than you can always use this
screen2.message = [[NSString alloc] initWithFormat:#"use what ever init methode that you want"];
and dont forget to release the screen2 before the end of the method to avoid memory leaks
Do you have a setter for Message? If not, is it a property? Either way, I would have a getter method, setMessage:(NSString *)msg with the following implementation:
- (void)setMessage:(NSString *)msg {
[message release];
message = [msg retain];
// put your code to modify your UI here
}
This way, you're tying the assignment of the variable with the update of the view.
You could create a new init method for ScreenTwoViewController. For example, - (id) initWithMessage:(NSString *)message.
To update the message just create a setter method - (void)setMessage:(NSString *)newMessage.
If I have a custom NSObject class called ProgramModel, does it get alloc/init -ed when I #property and #synthesize it from another class?
For instance, in a ProgramController class like this
// ProgramController.h
#import "ProgramModel.h"
#interface ProgramController : UIViewController {
ProgramModel *programModel;
}
#property (nonatomic, retain) ProgramModel *programModel;
// ProgramController.m
#import "ProgramController.h"
#implementation ProgramController
#synthesize programModel;
// etc
Do I also need to alloc/init in the initWithNibName or viewDidLoad, or is it already alloc/init-ed because of the property/synthesize?
You need to populate the property manually. The exception is if you have an IBOutlet property that you've connected in a nib file; that will get populated automatically when the nib is loaded.
I find that for view controllers the vast majority of properties are IBOutlets and properties that describe what the view will show, and the latter case is usually set by the object that creates the view controller. That will usually be the case for a view controller that shows a detail view for some object.
If you do have properties that are completely local to the view controller, a common pattern is to write your own getter and setter (rather than using #synthesize) and create the object in the getter if it doesn't exist. This lazy-loading behavior means you can easily free up resources in low-memory conditions, and that you only pay the cost of loading an object when you need it.
// simple lazy-loading getter
-(MyPropertyClass*)propertyName {
if(propertyIvarName == nil) {
propertyIvarName = [[MyPropertyClass alloc] init];
// ... other setup here
}
return propertyIvarName;
}
By default, all instance variables are zero'd out. In the case of objects, that means they're nil. If you want an initial value in the property, you need to put it there during your initializer/viewDidLoad method.
#property only declares the getter/setter methods.
#synthesize only generates the accessors for you.
They are not automatically assigned values, apart from the memory being zeroed. Additionally, you have to set them to nil in -dealloc to avoid a leak.
It also doesn't make sense to "alloc a property". An object property is a pointer. (And think of what happens if you have a linked list class...)
(N.B.: The property attributes also affect the #synthesized method, and the properties are also known to the runtime; see class_copyPropertyList() and friends.)
I have two properties setup as ViewControllers that each use different NIB file. (Male and Female Models, will function the same but are setup visually different.) I want to have one function to create the ViewController based on the NIB Name and ViewController I pass in.
What's happening is the ViewController property is not being retained. If I add the actual property name within the function and set it, the viewController is set and retains the ViewController. Here is what I have in the .m file (Only showing what is needed to get help on.) I've kept in the two comment lines that I tried to do determine where the problem was.
#synthesize femaleModelViewController;
#synthesize maleModelViewController;
- (void) loadModelViewControllerWithModelType:(NSString*) model ModelView:(ModelViewController *)modelViewController {
ModelViewController *viewController = [[ModelViewController alloc] initWithNibName:model bundle:nil];
// [self setFemaleModelViewController:viewController]; // I don't want to set the property here, I want to be able to pass it as an argument.
modelViewController = viewController;
// [modelViewController retain]; // I even tried to retain it do see if would but it doesn't.
[viewController release];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self loadModelViewControllerWithModelType:#"FemaleModel" ModelView:femaleModelViewController];
[self loadModelViewControllerWithModelType:#"MaleModel" ModelView:maleModelViewController];
}
In the .h file my Properties are setup like so:
#property (nonatomic, retain) ModelViewController *femaleModelViewController;
#property (nonatomic, retain) ModelViewController *maleModelViewController;
Are you trying to assign a new ModelViewController to maleModelViewController and femaleModelViewController? If so, you're going about it the wrong way.
Frankly, I'd do away with the loadModelViewControllerWithModelType:modelView: method altogether. All you would need to do in viewDidLoad is this:
maleModelViewController = [[ModelViewController alloc] initWithNibName:#"MaleModel"];
femaleModelViewController = [[ModelViewController alloc] initWithNibName:#"FemaleModel"];
(This assumes that maleModelViewController and femaleModelViewController are the instance variables backing the properties of the same name.)
When you pass in maleModelViewController and femaleModelViewController, you're not passing a reference to those variables, you're passing their values. Since they haven't been initialized, all you're doing is passing in nil. To do what you're trying to do, you'd need to pass a pointer to the variables (i.e. declare the parameter as ModelViewController **, pass it in as &maleModelViewController and &femaleModelViewController and assign it using *modelViewController = viewController. If you're used to using pass-by-reference friendly languages like C# or Java, you should read up on how it works in C. (The rules are the same in Objective-C as in C).
HOWEVER, that is still complete overkill for what you're trying to do here.
Also, your code would still not work because you turn around and release viewController. This would cause it to be immediately deallocated, since the only reference you had to it came from when you alloced it. You would be assigning a dead reference that would crash your program as soon as you tried to use it.