user2391236
user2391236

Reputation:

Dot syntax and square brackets

I am doing a tuturial on Lynda.com for objective-c, and ran accross this example code. This is a part of the ViewController.m file. The idea behind the exercise was to create a picker object with custom elements in it. The following code works just fine and gives me a picker with "happy" and "sad" as the options:

  @implementation ViewController

-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 1;
}

-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    return [[self moods] count];
}

-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    return self.moods[row];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.



    self.moods = @[@"happy",@"sad"];
}

However, I prefer square brackets to dot syntax and, as you can see I experimented in a few different places with it. Thereturn [[self moods] count was written as return [self.moods count] in the tutorial, but I wanted to use square brackets to verify that it still worked and I understood what was going on, so I changed it and it worked just fine. HOWEVER, I have been trying to do the same thing with the self.moods = @[@"happy",@"sad"]; because I don't like how it looks. I tried:

[[self moods] initWithObjects: @"happy",@"sad", nil];

But I just got a blank picker and a warning "expression result unused". I tried putting _moods = before that expression, and still got a blank picker. What is wrong here?

Upvotes: 0

Views: 161

Answers (4)

Michael Ho Chum
Michael Ho Chum

Reputation: 939

I assume you declared @property (strong, nonatomic) NSArray *moods; in the interface since self.moods works.

Setter and getter methods setMoods and getMoods are created automatically.

Here's how the dot syntax boils down to

// These are equivalent
self.moods = @[@"happy",@"sad"];
[self setMoods:@[@"happy",@"sad"]]; // Literal declaration
[self setMoods:[[NSArray alloc] initWithObjects:@"happy",@"sad",nil]]; // Full declaration

This works because you were using the "literal" way of declaring an NSArray* which includes both "allocation" and "initialization".

- (instancetype)initWithObjects: is an instance method which should be called on an instance variable already allocated with alloc. You tried to initialize a variable which has never been allocated in memory.

An slightly cleaner alternative would be:

[self setMoods:[NSArray arrayWithObjects:@"happy",@"sad",nil]];

arrayWithObjects: include both allocation and initialization.

Upvotes: 2

Brian Palma
Brian Palma

Reputation: 641

The reason that [[self moods] initWithObjects: @"happy",@"sad", nil]; is not doing what you expect is due to a misunderstanding in what is happening with regards to dot syntax and how it relates to message sending using square brackets.

Dot syntax is the "syntactic sugar" and recommended way of accessing properties of classes, such as the mood property from your question. Dot syntax is simply a shorthand for accessors (setters / getters) in Objective-C. A quick example might help clear this up.

When dot syntax finds itself on the right hand side of an assignment operator OR as the receiver of a message, the getter method is invoked.

// These two are equivalent
NSArray *allMoods = self.moods
NSArray *allMoods = [self moods]

// These two are equivalent
NSUInteger count = [self.moods count];
NSUInteger count = [[self moods] count];

When dot syntax finds itself on the left hand side of an assignment operator, the setter method is invoked.

// These two are equivalent
self.moods = @[@"happy", @"sad"];
[self setMoods:@[@"happy", @"sad"];

Using dot syntax is not only a nice shorthand, it makes your intentions clearer and newcomers to your code immediately aware that moods is a property of your class.

Also, the reason that [[self moods] initWithObjects: @"happy",@"sad", nil]; is not valid is because -initWithObjects: is an initializer of NSArray that should be called immediately following +alloc. In the piece of code above, [self moods] is returning an NSArray that already exists or lazily instantiating one. For completeness, -initWithObjects should be used as follows:

NSArray *myArray = [[NSArray alloc] initWithObjects:@"happy", @"sad", nil];

Upvotes: 2

Kevin OMara
Kevin OMara

Reputation: 433

You'll want to read up on the @property declaration and how it "synthesizes" getter and setter methods. What you want to do is "set" the moods property:

[self setMoods: @[@"happy",@"sad"]];

Upvotes: 1

odlund
odlund

Reputation: 247

the [self moods] way of referencing it can only be used on the right hand side of an expression, it's calling the getter for the property. self.moods = ... is actually syntactic sugar for [self setMoods:...]

so try [self setMoods:@[@"happy",@"sad"]]

Upvotes: 1

Related Questions