[ACCEPTED]-Confusion with header and Implementation files in Objective-C-properties

Accepted answer
Score: 84

I'll answer your questions below, but perhaps 111 the best way to learn this stuff is to read 110 some user-friendly notes intended for folks 109 new to the language, such as the Learn Objective-C tutorial over at cocoadevcentral.

An example

I'd 108 like to help answer your questions with 107 an example (I love learning by example). Let's 106 say you're a teacher writing a program that 105 asks students a particular yes/no question, and 104 keeps track of how many get it correct and 103 how many students it has asked.

Here is a 102 possible interface for this class:

@interface Question : NSObject {
  NSString* questionStr;
  int numTimesAsked;
  int numCorrectAnswers;
}

@property (nonatomic, retain) NSString* questionStr;
@property (nonatomic, readonly) int numTimesAsked;
@property (nonatomic) int numCorrectAnswers;
@property (nonatomic) int numWrongAnswers;

- addAnswerWithTruthValue: (BOOL) isCorrect;
@end

The three 101 variables inside the braces are instance variables, and every 100 instance of your class will have its own 99 values for each of those variables. Everything 98 outside the braces but before @end is a declaration 97 of a method (including the @property declarations).

(Side note: for many objects, it's useful to have retain properties, since you want to avoid the overhead of copying the object, and make sure it isn't released while you're using it. It's legal to retain an NSString as in this example, but it is often considered good practice to use copy instead of retain since an NSString* might actually point to an NSMutableString object, which may later change when your code expects it to stay the same.)

What @property does

When 96 you declare a @property, you're doing two things:

  1. Declaring a setter and getter method in the class's interface, and
  2. Indicating how the setter and getter behave.

For 95 the first one, it's enough to know that 94 this line:

@property (nonatomic, retain) NSString* questionStr;

is basically the same as this:

- (NSString*) questionStr;                           // getter
- (void) setQuestionStr: (NSString) newQuestionStr;  // setter

in 93 the header. You literally are declaring 92 those two methods; you can call them directly, or 91 use the dot notation as a shortcut to call 90 them for you.

The "basically" part 89 in "basically the same" is the 88 extra info given by keywords like nonatomic and retain.

The 87 nonatomic keyword indicates that they're not necessarily 86 thread-safe. The common retain keyword indicates 85 that the object retains any value that's 84 set, and releases previous values as they're 83 let go.

For example:

// The correct answer to both questions is objectively YES.
Question* myQuestion = [[Question alloc] init];
NSString* question1 = [[NSString alloc] initWithString:@"Is pizza tasty?"];
// question1 has retain count of 1, from the call to alloc
myQuestion.questionStr = question1;
// question1 now has a retain count of 2
NSString* question2 = [[NSString alloc] initWithString:@"Free iPhone?"];
myQuestion.questionStr = question2;
// question1 has a retain count of 1, and question2 has retain count of 2

If the @property declaration for 82 questionStr had been assign instead, then all the myQuestion.questionStr = statements 81 would not have made any changes at all to 80 the retain counts.

You can read a little more about properties here.

What IBOutlet and IBAction do

These are basically 79 no-op words which act only as a way to tell 78 Interface Builder which pieces of the header 77 file to pay attention to. IBOutlet literally becomes 76 an empty string when the compiler looks 75 at it, and IBAction becomes the void return value. We 74 do need them to work with Interface Builder, though, so 73 they are important -- just not to the compiler.

Quick note on C structs and arrow vs dot notation

By 72 the way, the data part of an Objective-C 71 object is very similar to a C struct. If 70 you have a pointer to a C struct, you can 69 use arrow notation -> to refer to a specific 68 part of the struct, like this:

struct MyStructType {
  int i;
  BOOL b;
};
struct MyStructType* myStruct;
myStruct->i = 3;
myStruct->b = TRUE;  // or YES in Objective-C.

This same 67 syntax works the same way in Objective-C:

Question* question = [[Question alloc] init];
question->questionStr = @"Is this a long answer?";  // YES

But 66 when you do this, there is no method call 65 happening behind the scenes, unlike the 64 dot notation. With the dot notation, you're 63 calling the setter (or getter if there's 62 no = afterwards), and these two lines are 61 the same:

question.questionStr = @"Chocolate?";
[question setQuestionStr:@"Chocolate?"];

It's often a good idea to avoid 60 the arrow notation in favor of the dot notation, since 59 the dot notation lets you enforce valid 58 state -- for example, that the pointers 57 your class has are always retained. You 56 can even disallow others from using the 55 arrow notation by declaring your instance 54 variables as @private; they can still use the getter 53 and setter to access it, if you declare 52 a @property for it.

What @synthesize does

Now, when you get around to actually 51 implementing your class, @synthesize says something 50 like "make sure the getter and setter 49 get implemented for this property." It 48 does not say "implement both of these 47 for me," because the compiler is polite 46 enough to check for your own implementation 45 first, and only fill in the pieces you've 44 missed. You don't have to use @synthesize at all, even 43 if you use @property out the wazoo -- you could always 42 just provide your implementations for your 41 setters and getters, if you're into that 40 sort of thing.

You probably noticed in the 39 Question interface above that there's a property 38 which is not an instance variable (numWrongAnswers), which 37 is fine because you're just declaring methods. In 36 the example code here, you can see how this 35 actually works:

@implementation Question

@synthesize questionStr, numTimesAsked, numCorrectAnswers;

- (void) setNumCorrectAnswers: (int) newCorrectAnswers {
  // We assume the # increases, and represents new answers.
  int numNew = newCorrectAnswers - numCorrectAnswers;
  numTimesAsked += numNew;
  numCorrectAnswers = newCorrectAnswers;
}

- (int) numWrongAnswers {
  return numTimesAsked - numCorrectAnswers;
}

- (void) setNumWrongAnswers: (int) newWrongAnswers {
  int numNew = newWrongAnswers - self.numWrongAnswers;
  numTimesAsked += numNew;
}

- (void) addAnswerWithTruthValue: (BOOL) isCorrect {
  if (isCorrect) {
    self.numCorrectAnswers++;
  } else {
    self.numWrongAnswers++;
  }
}

@end

One thing that's happening 34 here is we're faking an instance variable 33 called numWrongAnswers, which would be redundant information 32 if we stored it in the class. Since we 31 know numWrongAnswers + numCorrectAnswers = numTimesAsked at all times, we only need to 30 store any two of these three data points, and 29 we can always think in terms of the other 28 one by using the two values we do know. The 27 point here is to understand that a @property declaration 26 is really just about declaring a setter 25 and getter method, which usually corresponds 24 to an actual instance variable -- but not 23 always. The @synthesize keyword by default does correspond 22 to an actual instance variable, so that 21 it's easy for the compiler to fill in the 20 implementation for you.

Reasons to have separate .h and .m files

By the way, the whole 19 point of declaring methods in one file (the 18 .h header file) and defining their implementation 17 in another (the .m or methods file) is to 16 help decouple the code. For example, if 15 you only update one .m file in your project, you 14 don't have to recompile the other .m files, since 13 their object code will remain the same -- this 12 saves time. Another advantage is that you 11 can use a library that includes only header 10 files and pre-compiled object code, or even 9 dynamic libraries where you need the header 8 file so the compiler is aware of which methods 7 exist, but those methods aren't even linked 6 in with your executable file. These advantages 5 are hard to appreciate when you first start 4 coding, but just the logical breakdown and 3 encapsulation of implementation becomes 2 useful after a short while.

I hope that's 1 helpful!

Score: 1
  1. methods are defined outside of the braces 15 since the braces are meant to encapsulate 14 the state of the object which can be argued 13 does not include the instance or class methods.

  2. What 12 you are defining in the braces are instance 11 variables that can be referenced as self.ivar

  3. The 10 @property and @synthesize directives simply 9 setup accessors for you instance variables 8 so you can set them by doing self.ivar = someVar. So 7 in other words it sets up the "dot syntax" for 6 you to use.

and to answer your finale question: To 5 define a property or instance variable simply 4 declare it in your .h file as a variable 3 inside the braces. To setup accessor methods 2 on that same property you need to do BOTH 1 @property and @synthesize.

Score: 0
  1. Well that is just Objective C syntax, methods 15 and @property outside {} and variables inside 14 {}.

  2. @property is the way of telling that 13 you are going to write getter and setters 12 (kind of enforcing it), but you can write 11 getter/setter without setting them @property. @property 10 is in .h file because its declaration. And 9 why it is outside {}, well as i said before 8 its just the syntax, what we can do?

  3. @synthesis 7 will in actual implement getter and setters, if 6 you dont synthesis but you have set them 5 @property, you have to implement those getter 4 and setters by your hand. And @synthesis 3 is in .m file because its implementation.

Something 2 more for you to read on this subject can 1 be find here.

http://theocacao.com/document.page/510

Score: 0

The variables inside the brackets define 18 the physical structure of your class. Those are the actual 17 instance variables that store information.

The 16 stuff outside the brackets make up the class's 15 interface — methods and properties. A property 14 in and of itself does not reserve any storage 13 space or affect any variable — it just declares 12 a generic interface for accessing something. Remember 11 that a property doesn't have to have an 10 underlying instance variable — for example, the 9 totalPrice property in a ShoppingCart class 8 might dynamically sum the prices of all 7 the items in the cart.

Inside the implementation 6 file, you tell the class how to actually 5 do its work. For methods, obviously, you 4 just supply an implementation. For a property, you 3 can either provide accessor implementations 2 yourself or ask it to synthesize accessors 1 for an instance variable.

More Related questions