Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

PriapusZA

macrumors 6502a
Original poster
Oct 21, 2011
677
1
England
Hi all,

So this morning I took on the first homework set by the CS193p Stanford iOS programming course (Winter 2013)

The homework was to make the card "flip" through different suit / ranks.

Now this is how I first tried the challenge:

Code:
#import "CardGameViewController.h"
@interface CardGameViewController ()
@property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
@property(nonatomic) int flipCount;
@property (nonatomic, strong) PlayingCardDeck *deck;


@end

@implementation CardGameViewController
@synthesize deck;

- (PlayingCardDeck *)deck
{
    if (!deck) deck = [[PlayingCardDeck alloc]init];

    return deck;
}
-(void)setFlipCount:(int)flipCount
{
    _flipCount = flipCount;

    self.flipsLabel.text = [NSString stringWithFormat:@"Flips: %d", self.flipCount]; 
}

- (IBAction)flipCard:(UIButton *)sender
{
    sender.selected = !sender.isSelected;
    [sender setTitle:[_deck drawRandomCard].contents forState:UIControlStateSelected];
    self.flipCount++;
    NSLog (@"%@", [self.deck drawRandomCard].contents);
}

@end

So the property Playingcard deck inherits from another class deck - which has the method drawRandomCard.

Deck inherits from another class Card.

Now the above code would give my NSLog statement (null) and for some reason and I couldn't access my deck property directly without the
Code:
@synthesize deck;

This version of the code works perfectly:

Code:
#import "CardGameViewController.h"
@interface CardGameViewController ()
@property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
@property(nonatomic) int flipCount;
@property (nonatomic, strong) PlayingCardDeck *deck;


@end

@implementation CardGameViewController


- (PlayingCardDeck *)deck
{
    if (!_deck) _deck = [[PlayingCardDeck alloc]init];

    return _deck;
}
-(void)setFlipCount:(int)flipCount
{
    _flipCount = flipCount;

    self.flipsLabel.text = [NSString stringWithFormat:@"Flips: %d", self.flipCount]; 
}

- (IBAction)flipCard:(UIButton *)sender
{
    sender.selected = !sender.isSelected;
    [sender setTitle:[self.deck drawRandomCard].contents forState:UIControlStateSelected];
    self.flipCount++;
    NSLog (@"%@", [self.deck drawRandomCard].contents);
}

@end


My understanding of self:

It calls the object calling the method. Its calling itself.

Questions:

1. Why did the first version of the code not work?
2. Can someone try explain self a little better for me? :(

If I had understood self - I would have completed the homework all on my own - however I took a look at an example and I was only missing the self keyword...so close!! :mad::(
 
If I had understood self - I would have completed the homework all on my own - however I took a look at an example and I was only missing the self keyword...so close!! :mad::(

When self is used together with strictly (in the .m file) synthesized properties, it makes sure the auto-generated accessor / mutator methods are used and you're not directly, without going thru the generated methods, assigning values.

When not using ARC, ALWAYS use self when assigning a value to an object reference - it makes sure the system makes sure the previous content, if any, is released, and the new one is properly retained. In ARC you should use self too.

In earlier (3.x) Xcode versions, you didn't get compile-time errors if you forgotten adding the self prefix. Fortunately, Xcode 4.x is much more intelligent in this respect - this is why your first app doesn't compile.

It's only in very few cases that self shouldn't be used.
 
When self is used together with strictly (in the .m file) synthesized properties, it makes sure the auto-generated accessor / mutator methods are used and you're not directly, without going thru the generated methods, assigning values.

When not using ARC, ALWAYS use self when assigning a value to an object reference - it makes sure the system makes sure the previous content, if any, is released, and the new one is properly retained. In ARC you should use self too.

In earlier (3.x) Xcode versions, you didn't get compile-time errors if you forgotten adding the self prefix. Fortunately, Xcode 4.x is much more intelligent in this respect - this is why your first app doesn't compile.

It's only in very few cases that self shouldn't be used.

Thanks for explaining. That helps a little.

For some reason I was under the impression we only use self when we are referring to the class we're in. Not the property within the .m file.

So I can access all my properties instance variables using self? (Within that .m file? )
 
Thanks for explaining. That helps a little.

For some reason I was under the impression we only use self when we are referring to the class we're in. Not the property within the .m file.

So I can access all my properties instance variables using self? (Within that .m file? )

Yes, and you should always do so, most importantly when assigning values to them. (For read-only access, that is, as an rvalue, self isn't strictly needed in most cases as no behind-the-curtains releases/ retains need to take place. You, nevertheless, can always prefix those properties too. I too do so.)
 
Yes, and you should always do so, most importantly when assigning values to them. (For read-only access, that is, as an rvalue, self isn't strictly needed in most cases as no behind-the-curtains releases/ retains need to take place. You, nevertheless, can always prefix those properties too. I too do so.)

Ah okay. Starting to make sense. Without the self prefix - we would be accessing the ivars directly - bypassing the setters and getters?
 
Ah okay. Starting to make sense. Without the self prefix - we would be accessing the ivars directly - bypassing the setters and getters?

Yup, unless you rename them in @synthesize like

@synthesize arr=__myaarr;

where "arr" is the property (e.g., @property (retain) NSMutableArray* arr;) and "__myaarr" is just the name of the ivar synthesized by the system when using the @synthesize directive liek above.

If you don't rename the property (more precisely, tell the system under which name the synthesized ivar should be accessed), you'll be able to access it directly, without self. If you do add such an explicit renaming to all of your must-be-retained properties, you'll no longer be able to errorenously write

arr = [[NSMutableArray alloc] init];

instead of

self.arr = [[NSMutableArray alloc] init];

as there's no 'arr' ivar synthesized any more, but '__myaarr'. This means the latter would work (but you won't want to use it as the whole point of renaming is making sure you don't accidentally use an ivar variable name without self. in front of it)

__myaarr = [[NSMutableArray alloc] init];
 
Yup, unless you rename them in @synthesize like

@synthesize arr=__myaarr;

where "arr" is the property (e.g., @property (retain) NSMutableArray* arr;) and "__myaarr" is just the name of the ivar synthesized by the system when using the @synthesize directive liek above.

If you don't rename the property (more precisely, tell the system under which name the synthesized ivar should be accessed), you'll be able to access it directly, without self. If you do add such an explicit renaming to all of your must-be-retained properties, you'll no longer be able to errorenously write

arr = [[NSMutableArray alloc] init];

instead of

self.arr = [[NSMutableArray alloc] init];

as there's no 'arr' ivar synthesized any more, but '__myaarr'. This means the latter would work (but you won't want to use it as the whole point of renaming is making sure you don't accidentally use an ivar variable name without self. in front of it)

__myaarr = [[NSMutableArray alloc] init];

100% clear now why my first version didn't work at all and why we rename the synthesize variables.

Thank you so much for taking the time to explain.

So much to learn as a new iOS developer! :eek::cool:
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.