I am new to Iphone programming. Please correct me where am I going wrong.
I have two viewcontrollers
viewcontroller1 viewcontroller2
In viewcontroller1,
-(IBAction) getQuestions:(id)sender
{
NSLog(#"In get questions..");
[[self viewcontroller2] initWithData:userInfo];
[self presentModalViewController:viewcontroller2 animated:YES];
[quesions autorelease];
}
In viewController2 I have the following code.
-(id)initWithData:(NSMutableDictionary*)data
{
self = [super init];
if(self)
{
userInfo = [[NSMutableDictionary alloc] initWithDictionary:data];
}
return self;
}
-(IBAction) getQuesionAfterPopUp:(id) sender
{
NSLog(#"In get question..After popup...%#",userInfo);
}
For some reason "userInfo" is null. Why is it null even after using init with data.
You didn't initialize correctly, therefore the instance variable userInfo is not accessible.
Initialization should look like this:
- (id)initWithData:(NSMutableDictionary *)data
{
self = [super init]; // 'self' and it's instance variables are accessible at this point ...
if (self)
{
userInfo = // etc...
}
return self;
}
You might want to read up on this link for more information on how to implement designated initializers. Especially focus on the topic Implementing an Initializer.
in the above code you don't retain your userInfo object. Try
userInfo = [[[NSMutableDictionary alloc] initWithDictionary:data]]retain];
Or if userInfo is a property like:
#property (nonatomic, retain)
Try:
self.userInfo = [[NSMutableDictionary alloc] initWithDictionary:data]];
Which will automatically retain the userInfo. Please note by not calling self you are assigning straight to the instance variable.
Finally, make sure that the data object is not empty
Related
I've tried to init/alloc it in initWithFrame but then objects wouldn't get added.
It'd only work in this method I'm calling but I call this method each time user refreshes the view so it'd init/alloc hundred times.
Not sure why it won't just work in initWithFrame.
I need to know the right way to init and add..!
-(void)queryParseMethod {
self.imageFilesArray = nil;
self.imageFilesArray = [[NSMutableArray alloc]init];
[self.imageFilesArray addObjectsFromArray:objects];
if (!error) {
for (PFObject *object in objects) {
int index = (int)[self.favArray indexOfObject:[object objectId]];
[self.imageFilesArray replaceObjectAtIndex:index withObject:object];
}
[self.favCV reloadData];
}}
Why not just:
if (self.imageFilesArray == nil) {
self.imageFilesArray = [[NSMutableArray alloc] init];
[self.imageFilesArray addObjectsFromArray:objects];
}
And make sure that imageFilesArray is a strong property.
Your most likely problem is that initWithFrame: isn't being called. If this view comes out of a storyboard, then you need to put this in awakeFromNib, since storyboard/nib-loaded objects initialize with initWithCoder:, not their designated initializer.
You generally don't want to try to do initialization in initWithCoder: because it's called too early. awakeFromNib is called after all your IBOutlets are assigned.
It is very common for experienced devs to break initialization out into its own method like this:
- (void)setup {
// Do your setup here
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setup];
}
}
- (void)awakeFromNib {
[self setup];
}
Doing it this way makes sure that the object is initialized in either case.
Another common solution is lazy initialization, particularly for things like NSMutableArray:
#interface MyView
#property (nonatomic, readonly, strong) NSMutableArray *imageFilesArray;
#end
#implementation MyView
- (NSMutableArray *)imageFilesArray {
if (_imageFilesArray == nil) {
_imageFilesArray = [NSMutableArray new];
}
return _imageFilesArray;
}
I have a property that gets set when initiating a new view controller.
- (IBAction)headerPressed:(UIButton *)sender {
RouteViewController *route = [[RouteViewController alloc] initWithRoute:[[Route getRoute:TEST_ROUTE] autorelease]];
[[self navigationController] pushViewController:circle animated:NO];
}
in the new view, which is a UIViewController
RouteViewController.h
#interface =RouteViewController : UIViewController <MKMapViewDelegate> {
Route *r;
}
-(id)initWithRoute:(Route *)route;
#property (retain, nonatomic) Route *r;
RouteViewController.m
-(id)initWithRoute:(Route *)route{
self = [super init];
r = route;
return self;
}
- (void)loadView {
[super loadView];
NSLog(#"TEST: %d", r.Route); // throws exception. Actually ANY time I access my r property
}
r.Route is the int value that the const TEST_ROUTE contains.
NOW, when I setup my breakpoint, AT the time of the NSLog, the inspector shows my object contains
Self >
r >
Route: 1
and
r >
Route: 1
So the property is available, and it DOES contain the correct data. But when i try ACCESSING the property, it throws an EXC_BAD_ACCESS.
Thoughts? :) (This is killing me here!)
There are a few problems here:
RouteViewController *route = [[RouteViewController alloc] initWithRoute:[[Route getRoute:TEST_ROUTE] autorelease]];
I think the autorelease message should be sent to the RouteViewController here and not the Route object, as the getRoute method should return an autoreleased object due to the naming convention.
i.e.
RouteViewController *route = [[[RouteViewController alloc] initWithRoute:[Route getRoute:TEST_ROUTE]] autorelease];
You need to retain ownership of the Route object passed into the initWithRoute method:
Either:
-(id)initWithRoute:(Route *)route{
self = [super init];
r = [route retain];
return self;
}
or:
-(id)initWithRoute:(Route *)route{
self = [super init];
self.r = route;
return self;
}
It looks like you're not using ARC, but you're also not retaining route in your init method. Change this:
r = route;
to this:
r = [route retain];
I'm having problems with a leak in the init method of a class I have created. To keep it simple, I have the following (simplified) problem:
ViewController initialises an instance of
ClipData class which initialises an instance of
AnimationData class which initialise a string
ViewController:
myClipData = [[ClipData alloc] init];
ClipData:
- (id)init
{
self = [super init];
if (self) {
animData = [[AnimationData alloc] init]; //LEAK HERE
}
return self;
}
AnimationData:
- (id)init
{
self = [super init];
if (self) {
name = [NSString string];
}
return self;
}
All the objects in the classes are declared as (nonatomic, retain). I'm aware that doing this bumps up the retain count, but how do I initialise the AnimationData without leaking the animData???
Probably a very stupid question, so any help much appreciated.
Thanks,
Duncs
You are never releasing the animData. You need to add dealloc to your class:
- (void)dealloc {
[animData release];
[super dealloc];
}
Similarly, you need to add a similar dealloc to AnimationData.
On a related note, you need to retain and later release the string created in -[AnimationData init], what you are doing right now is essentially a noop, except that it leaves behind a garbled pointer.
When you have an alloc you must also have a release.
You should also reference the properties through self so you access the properties rather than the underlying members.
So you should really do :
ClipData *clip = [[ClipData alloc] init];
self.myClipData = clip;
[clip release];
And
if (self) {
AnimationData *data = [[AnimationData alloc] init];
self.animData = data;
[data release];
}
Make sure you also release the properties in the dealloc of the class by setting them to nil.
self.myClipData = nil;
self.animData = nil;
Why Im having a memory leak here:
.h:
#property (nonatomic, retain) NSDictionary *info;
and then in my .m:
#synthesize info = _info;
and Im having one leak here:
- (id)initWithData:(NSDictionary *)data
{
self = [super init];
if (self) {
self.info = [[NSDictionary alloc] initWithDictionary:data];
}
return self;
}
And another leak here:
-(void)dealloc {
[self.info release];
[super dealloc];
}
Your leak stems from your property declaration and the way you assign it, when you declare a property as "retain" using the setter will retain the var for you, so doing
self.info = [[NSDictionary alloc] initWithDictionary:data];
Retains the var, and since alloc also retain the var you get a +2 retain count, you should either autorelease the object or assign it like
_info = [[NSDictionary alloc] initWithDictionary:data];
also when you release a property do so by setting it to nil
self.info=nil
Your constructor should use
self.info = [NSDictionary dictionaryWithDictionary:data];
Your dealloc should be simplified to
- (void)dealloc {
self.info = nil;
[super dealloc];
}
If you have an object with a property which has a retain setter, which of these is best practice?
1
-(id)init {
if((self = [super init])) {
self->_retainingProperty = [[NSObject alloc] init];
}
return self;
}
2
-(id)init {
if((self = [super init])) {
self.retainingProperty = [[NSObject alloc] init];
[self.retainingProperty release];
}
return self;
}
3
-(id)init {
if((self = [super init])) {
NSObject *obj = [[NSObject alloc] init];
self.retainingProperty = obj;
[obj release];
}
return self;
}
All of these would be coupled with a release in dealloc
Perhaps there is another way I've missed.
I generally just do:
- (id ) init
{
self = [super init];
if ( self )
{
retainingProperty = [[NSObject alloc] init];
}
return self;
}
I would not suggest #2 or #3, unless you are aware they might invoke KVO stuff that you do not intend.
All of the above are fine and broadly equivalent. You can also access the member variable using just its name:
-(id)init {
if((self = [super init])) {
_retainingProperty = [[NSObject alloc] init];
}
return self;
}
Property setters are really just convenience methods to ensure the retain/release dance is done correctly, so if you are doing things correctly you can do without them.
If you've added some custom logic to the setter method, you may want to ensure it's called by always using the property setter syntax. Or alternatively, you may want to deliberately sidestep that logic in some instances, and therefore avoid using it some of the time. It's up to you - whatever works for your use case.
At least two other ways immediately spring to mind. There's direct ivar access:
- (id) init
{
if ( self = [super init] )
{
_retainingProperty = [[NSObject alloc] init];
}
return self;
}
Or you could use the autorelease pool:
- (id) init
{
if ( self = [super init] )
{
self._retainingProperty = [[[NSObject alloc] init] autorelease];
}
return self;
}
Depending on the class of the property, there may also be convenience methods equivalent to the latter.
Personally, I would pretty much always go with the direct ivar access. It is usually considered bad form to call property accessors in init, because they may have side effects that you wouldn't want to happen while the object is incompletely initialised.
Similar considerations apply in dealloc, btw: it's better to release your ivars directly rather than using the property accessors.