Reputation:
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
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
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
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
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