objective C study 요약
1. 오브젝티브 C 2.0은 C 랭귀지로 핸드폰을 개발했던 나로서는 다소 생소하다.
하지만 많은 유사점을 갖고 있다. C++은 공부했지만, embedded linux를 주로 하다보니 업무적으로 C++를 사용하지 않았다, C++은 MFC할때 잠간 사용했다.
하지만 오브젝티브 C는 전반적으로 C++의 특성을 갖고 있다. 아이폰을 개발하려면, 먼저 이것을 독파해야 하는데, 처음에는 @interface, @implementation 이것에 대해서 공부해야 한다.
property, 그리고, cocoa framework,
아이폰 개발하려고 기존 샘플소스를 보면 도통 알수가 없는 암호로 보인다.
처음에 Beginning iphone 3 developemnt Exploring the iPhone SDK를 아이폰 어플 개발에 도전하고자 반즈앤노블에서 사서 공부를 하다보니 소스를 접하고 나서, 난관에 부딪쳤다.
그래서, 아마존에서 돈을 아끼려고 5일을 기다렸다가, Programming in Objective-C 2.0을 샀다.
하지만, 약간 이상한 방식의 언어에 약간 난감함을 느꼈다, 그것도 원서로 읽다보니, 하지만, 차츰, for문, struct, union 이런거는 C 랭귀지로 삼성에서 휴대폰 개발할때 대부분 C언어의 온갖 난해한 알고리즘이 다 구사된 핸드폰을 마스터한 나로서는 C 랭귀지는 익숙해서, 그런 부분은 어려움이 없었고, 훍어지나가다시피 했다. 하지만, 그래도, 아직은 익숙치 않은 오브젝티브C 언어의 생소한 부분들을 정리하기로 했다.
기본적인 프로그램들은 굳이 짜보지않아도, 읽고만 넘어가면 되니까, 그런 부분은 자신감이 생기는데, 나머지 부분들은 좀 익숙해질 필요가 있어서, 이 시리즈를 집필해가면서 무료한 나의 아이폰 어플 도전기를 쓰고자 한다.
Learning Objective-C: A Primer
The Objective-C language is a simple computer language designed to enable sophisticated object-oriented programming. Objective-C extends the standard ANSI C language by providing syntax for defining classes, and methods, as well as other constructs that promote dynamic extension of classes. (This document doesn’t attempt to teach any aspects of C itself. If you’re not familiar with of the language, you should learn about the basics before you proceed.)
If you have programmed with object-oriented languages before, the following information should help you learn the basic syntax of Objective-C. Many of the traditional object-oriented concepts, such as encapsulation, inheritance, and polymorphism, are all present in Objective-C. There are a few important differences, but those differences are called out in this article and more detailed information is available if you need it.
If you have never programmed using an object-oriented language before, you need to have at least a basic understanding of the associated concepts before proceeding. The use of objects and object-oriented design patterns is fundamental to the design of Cocoa applications, and understanding how they interact is critical to creating your applications. For an overview of concepts, see Object-Oriented Programming with Objective-C. In addition, see Cocoa Fundamentals Guide for information about the design patterns used in Cocoa.
For full details of the Objective-C language and syntax, see The Objective-C 2.0 Programming Language.
Objective-C: A Superset of C
Objective-C is a superset of the ANSI version of the C programming language and supports the same basic syntax as C. As with C code, you define header files and source files to separate public declarations from the implementation details of your code. Objective-C header files use the file extensions listed in Table 1.
Table 1 File extensions for Objective-C code
ExtensionSource type.hHeader files. Header files contain class, type, function, and constant declarations..mSource files. This is the typical extension used for source files and can contain both Objective-C and C code..mmSource files. A source file with this extension can contain C++ code in addition to Objective-C and C code. This extension should be used only if you actually refer to C++ classes or features from your Objective-C code.When you want to include header files in your source code, you typically use a #import directive. This is like #include, except that it makes sure that the same file is never included more than once. The Objective-C samples and documentation all prefer the use of #import, and your own code should too.
Classes
As in most other object-oriented languages, classes in Objective-C provide the basic construct for encapsulating some data with the actions that operate on that data. An object is a runtime instance of a class, and contains its own in-memory copy of the instance variables declared by that class and pointers to the methods of the class.
The specification of a class in Objective-C requires two distinct pieces: the interface and the implementation. The interface portion contains the class declaration and defines the instance variables and methods associated with the class. The interface is usually in a .h file. The implementation portion contains the actual code for the methods of the class. The implementation is usually in a .m file.
Figure 1 shows the syntax for declaring a class called MyClass, which inherits from the NSObject base class. The class declaration always begins with the @interface compiler directive and ends with the @end directive. Following the class name (and separated from it by a colon) is the name of the parent class. The instance (or member) variables of the class are declared in a code block that is delineated by braces ({ and }). Following the instance variable block is the list of methods declared by the class. A semicolon character marks the end of each instance variable and method declaration.
Figure 1 A class declaration
Note: Although this class declaration declares only methods, classes can also declare properties. For more information on properties, see “Declared Properties”.
When storing objects in variables, you always use a pointer type. Objective-C supports both strong and weak typing for variables containing objects.
Strongly typed pointers include the class name in the variable type declaration.
Weakly typed pointers use the type id for the object instead.
Weakly typed pointers are used frequently for things such as collection classes, where the exact type of the objects in a collection may be unknown. If you are used to using strongly typed languages, you might think that the use of weakly typed variables would cause problems, but they actually provide tremendous flexibility and allow for much greater dynamism in Objective-C programs.
The following example shows strongly and weakly typed variable declarations:
MyClass *myObject1; // Strong typing
id myObject2; // Weak typing
Notice the * in the first declaration. In Objective-C, object references are pointers. If this doesn’t make complete sense to you, don’t worry—you don’t have to be an expert with pointers to be able to start programming with Objective-C. You just have to remember to put the * in front of the variable names for strongly-typed object declarations.
Methods and Messaging
A class in Objective-C can declare two types of methods:
instance methods and class methods.
An instance method is a method whose execution is scoped to a particular instance of the class. In other words, before you call an instance method, you must first create an instance of the class.
Class methods, by comparison, do not require you to create an instance, but more on that later.
The declaration of a method consists of the method type identifier, a return type, one or more signature keywords, and the parameter type and name information. Figure 2 shows the declaration of the insertObject:atIndex: instance method.
Figure 2 Method declaration syntax
This declaration is preceded by a minus (-) sign, which indicates that this is an instance method.
The method’s actual name (insertObject:atIndex:) is a concatenation of all of the signature keywords, including colon characters. The colon characters declare the presence of a parameter. If a method has no parameters, you omit the colon after the first (and only) signature keyword. In this example, the method takes two parameters.
When you want to call a method, you do so by messaging an object. A message is the method signature, along with the parameter information the method needs. All messages you send to an object are dispatched dynamically, thus facilitating the polymorphic behavior of Objective-C classes.
Messages are enclosed by brackets ([ and ]). Inside the brackets,
the object receiving the message is on the left side and
the message (along with any parameters required by the message) is on the right.
For example, to send the insertObject:atIndex: message to an object in the myArray variable, you would use the following syntax:
[myArray insertObject:anObject atIndex:0];
To avoid declaring numerous local variables to store temporary results, Objective-C lets you nest messages. The return value from each nested message is used as a parameter, or as the target, of another message. For example, you could replace any of the variables used in the previous example with messages to retrieve the values.
Thus, if you had another object called myAppObject that had methods for accessing the array object and the object to insert into the array, you could write the preceding example to look something like the following:
[[myAppObject theArray] insertObject:[myAppObject objectToInsert] atIndex:0];
Objective-C also provides a dot syntax for invoking accessor methods. Accessor methods get and set the state of an object, and typically take the form -(type)propertyName and -(void)setPropertyName:(type). Using dot syntax, you could rewrite the previous example as:
[myAppObject.theArray insertObject:[myAppObject objectToInsert] atIndex:0];
You can also use dot syntax for assignment:
myAppObject.theArray = aNewArray;
This is simply a different syntax for writing, [myObject setTheArray:aNewArray];.
Although the preceding examples sent messages to an instance of a class, you can also send messages to the class itself. When messaging a class, the method you specify must be defined as a class method instead of an instance method. You can think of class methods as something akin to (but not exactly like) static members in a C++ class.
You typically use class methods as factory methods to create new instances of the class or for accessing some piece of shared information associated with the class. The syntax for a class method declaration is identical to that of an instance method, with one exception. Instead of using a minus sign for the method type identifier, you use a plus (+) sign.
The following example illustrates how you use a class method as a factory method for a class. In this case, the array method is a class method on the NSArray class—and inherited by NSMutableArray—that allocates and initializes a new instance of the class and returns it to your code.
NSMutableArray *myArray = nil; // nil is essentially the same as NULL
// Create a new array and assign it to the myArray variable.
myArray = [NSMutableArray array];
Listing 1 shows the implementation of MyClass from the preceding example. Like the class declaration, the class implementation is identified by two compiler directives—here, @implementation and @end. These directives provide the scoping information the compiler needs to associate the enclosed methods with the corresponding class. A method’s definition therefore matches its corresponding declaration in the interface, except for the inclusion of a code block.
Listing 1 A class implementation
@implementation MyClass
- (id)initWithString:(NSString *)aName
{
if (self = [super init]) {
name = [aName copy];
}
return self;
}
+ (MyClass *)createMyClassWithString: (NSString *)aName
{
return [[[self alloc] initWithString:aName] autorelease];
}
@end
Declared Properties
Declared properties are a convenience notation used to replace the declaration and, optionally, implementation of accessor methods.
You include property declarations with the method declarations in your class interface. The basic definition uses the @property compiler directive, followed by the type information and name of the property. You can also configure the property with custom options, which define how the accessor methods behave. The following example shows a few simple property declarations:
@property BOOL flag;
@property (copy) NSString *nameObject; // Copy the object during assignment.
@property (readonly) UIView *rootView; // Declare only a getter method.
Each readable property specifies a method with the same name as the property. Each writable property specifies an additional method of the form setPropertyName:, where the first letter of the property name is capitalized.
In your class implementation, you can use the @synthesize compiler directive to ask the compiler to generate the methods according to the specification in the declaration:
@synthesize flag;
@synthesize nameObject;
@synthesize rootView;
You can combine the @synthesize statements in a single line if you want:
@synthesize flag, nameObject, rootView;
Practically speaking, properties reduce the amount of redundant code you have to write. Because most accessor methods are implemented in similar ways, properties eliminate the need to implement a getter and setter method for each property exposed in the class. Instead, you specify the behavior you want using the property declaration and then synthesize actual getter and setter methods based on that declaration at compile time.
For information on how to declare properties in your own classes, read Declared Properties in The Objective-C 2.0 Programming Language.
Strings
As a superset of C, Objective-C supports the same conventions for specifying strings as C. In other words, single characters are enclosed by single quotes and strings of characters are surrounded by double quotes. However, most Objective-C frameworks do not use C-style strings very often. Instead, most frameworks pass strings around in NSString objects.
The NSString class provides an object wrapper for strings that has all of the advantages you would expect, including built-in memory management for storing arbitrary-length strings, support for Unicode, printf-style formatting utilities, and more. Because such strings are used commonly though, Objective-C provides a shorthand notation for creating NSString objects from constant values. To use this shorthand, all you have to do is precede a normal, double-quoted string with the @ symbol, as shown in the following examples:
NSString *myString = @”My String\n”;
NSString *anotherString = [NSString stringWithFormat:@"%d %s", 1, @"String"];
// Create an Objective-C string from a C string
NSString *fromCString = [NSString stringWithCString:"A C string" encoding:NSASCIIStringEncoding];
Protocols
Protocols declare methods that can be implemented by any class. Protocols are useful in at least three situations:
To declare methods that others are expected to implement
To declare the interface to an object while concealing its class
To capture similarities among classes that are not hierarchically related
Declaring Interfaces for Others to Implement
Class and category interfaces declare methods that are associated with a particular class—mainly methods that the class implements. Informal and formal protocols, on the other hand, declare methods that are independent of any specific class, but which any class, and perhaps many classes, might implement.
A protocol is simply a list of method declarations, unattached to a class definition. For example, these methods that report user actions on the mouse could be gathered into a protocol:
- (void)mouseDown:(NSEvent *)theEvent;
- (void)mouseDragged:(NSEvent *)theEvent;
- (void)mouseUp:(NSEvent *)theEvent;
Protocols and Delegates
A protocol declares methods that can be implemented by any class. Protocols are not classes themselves. They simply define an interface that other objects are responsible for implementing. When you implement the methods of a protocol in one of your classes, your class is said to conform to that protocol.
Protocols are used frequently to specify the interface for delegate objects. A delegate object is an object that acts on behalf of, or in coordination with, another object. The best way to look at the interplay between protocols, delegates, and other objects is to look at an example.
The UIApplication class implements the required behavior of an application. Instead of forcing you to subclass UIApplication to receive simple notifications about the current state of the application, the UIApplication class delivers those notifications by calling specific methods of its assigned delegate object. An object that implements the methods of the UIApplicationDelegate protocol can receive those notifications and provide an appropriate response.
The declaration of a protocol looks similar to that of a class interface, with the exceptions that protocols do not have a parent class and they do not define instance variables. The following example shows a simple protocol declaration with one method:
@protocol MyProtocol
- (void)myProtocolMethod;
@end
In the case of many delegate protocols, adopting a protocol is simply a matter of implementing the methods defined by that protocol. There are some protocols that require you to state explicitly that you support the protocol, and protocols can specify both required and optional methods. As you get further into your development, however, you should spend a little more time learning about protocols and how they are used by reading Protocols in The Objective-C 2.0 Programming Language.
For More Information
The preceding information was intended primarily to familiarize you with the basics of the Objective-C language. The subjects covered here reflect the language features you are most likely to encounter as you read through the rest of the documentation. These are not the only features of the language though, and you are encouraged to read more about the language in The Objective-C 2.0 Programming Language.
The Scope of Instance Variables
Although they’re declared in the class interface, instance variables are more a matter of the way a class is implemented than of the way it’s used. An object’s interface lies in its methods, not in its internal data structures.
Often there’s a one-to-one correspondence between a method and an instance variable, as in the following example:
- (BOOL)isFilled
{
return filled;
}
But this need not be the case. Some methods might return information not stored in instance variables, and some instance variables might store information that an object is unwilling to reveal.
As a class is revised from time to time, the choice of instance variables may change, even though the methods it declares remain the same. As long as messages are the vehicle for interacting with instances of the class, these changes won’t really affect its interface.
To enforce the ability of an object to hide its data, the compiler limits the scope of instance variables—that is, limits their visibility within the program. But to provide flexibility, it also lets you explicitly set the scope at three different levels. Each level is marked by a compiler directive:
DirectiveMeaning@privateThe instance variable is accessible only within the class that declares it.@protectedThe instance variable is accessible within the class that declares it and within classes that inherit it.@publicThe instance variable is accessible everywhere.@packageUsing the modern runtime, an @package instance variable acts like @public inside the image that implements the class, but @private outside.
This is analogous to private_extern for variables and functions. Any code outside the class implementation’s image that tries to use the instance variable will get a link error. This is most useful for instance variables in framework classes, where @private may be too restrictive but @protected or @public too permissive.This is illustrated in Figure 2-1.
Figure 2-1 The scope of instance variables
A directive applies to all the instance variables listed after it, up to the next directive or the end of the list. In the following example, the age and evaluation instance variables are private, name, job, and wage are protected, and boss is public.
@interface Worker : NSObject
{
char *name;
@private
int age;
char *evaluation;
@protected
id job;
float wage;
@public
id boss;
}
By default, all unmarked instance variables (like name above) are @protected.
All instance variables that a class declares, no matter how they’re marked, are within the scope of the class definition. For example, a class that declares a job instance variable, such as the Worker class shown above, can refer to it in a method definition:
- promoteTo:newPosition
{
id old = job;
job = newPosition;
return old;
}
Obviously, if a class couldn’t access its own instance variables, the instance variables would be of no use whatsoever.
Normally, a class also has access to the instance variables it inherits. The ability to refer to an instance variable is usually inherited along with the variable. It makes sense for classes to have their entire data structures within their scope, especially if you think of a class definition as merely an elaboration of the classes it inherits from. The promoteTo: method illustrated earlier could just as well have been defined in any class that inherits the job instance variable from the Worker class.
However, there are reasons why you might want to restrict inheriting classes from directly accessing an instance variable:
Once a subclass accesses an inherited instance variable, the class that declares the variable is tied to that part of its implementation. In later versions, it can’t eliminate the variable or alter the role it plays without inadvertently breaking the subclass.
Moreover, if a subclass accesses an inherited instance variable and alters its value, it may inadvertently introduce bugs in the class that declares the variable, especially if the variable is involved in class-internal dependencies.
To limit an instance variable’s scope to just the class that declares it, you must mark it @private. Instance variables marked @private are only available to subclasses by calling public accessor methods, if they exist.
At the other extreme, marking a variable @public makes it generally available, even outside of class definitions that inherit or declare the variable. Normally, to get information stored in an instance variable, other objects must send a message requesting it. However, a public instance variable can be accessed anywhere as if it were a field in a C structure. For example:
Worker *ceo = [[Worker alloc] init];
ceo->boss = nil;
Note that the object must be statically typed.
Marking instance variables @public defeats the ability of an object to hide its data. It runs counter to a fundamental principle of object-oriented programming—the encapsulation of data within objects where it’s protected from view and inadvertent error. Public instance variables should therefore be avoided except in extraordinary cases.
Messages to self and super
Objective-C provides two terms that can be used within a method definition to refer to the object that performs the method—self and super.
Suppose, for example, that you define a reposition method that needs to change the coordinates of whatever object it acts on. It can invoke the setOrigin:: method to make the change. All it needs to do is send a setOrigin:: message to the same object that the reposition message itself was sent to. When you’re writing the reposition code, you can refer to that object as either self or super. The reposition method could read either:
- reposition
{
…
[self setOrigin:someX :someY];
…
}
or:
- reposition
{
…
[super setOrigin:someX :someY];
…
}
Here, self and super both refer to the object receiving a reposition message, whatever object that may happen to be. The two terms are quite different, however. self is one of the hidden arguments that the messaging routine passes to every method; it’s a local variable that can be used freely within a method implementation, just as the names of instance variables can be. super is a term that substitutes for self only as the receiver in a message expression. As receivers, the two terms differ principally in how they affect the messaging process:
self searches for the method implementation in the usual manner, starting in the dispatch table of the receiving object’s class. In the example above, it would begin with the class of the object receiving the reposition message.
super starts the search for the method implementation in a very different place. It begins in the superclass of the class that defines the method where super appears. In the example above, it would begin with the superclass of the class where reposition is defined.
Wherever super receives a message, the compiler substitutes another messaging routine for the objc_msgSend function. The substitute routine looks directly to the superclass of the defining class—that is, to the superclass of the class sending the message to super—rather than to the class of the object receiving the message.
An Example
The difference between self and super becomes clear in a hierarchy of three classes. Suppose, for example, that we create an object belonging to a class called Low. Low’s superclass is Mid; Mid’s superclass is High. All three classes define a method called negotiate, which they use for a variety of purposes. In addition, Mid defines an ambitious method called makeLastingPeace, which also has need of the negotiate method. This is illustrated in Figure 2-2:
Figure 2-2 High, Mid, Low
We now send a message to our Low object to perform the makeLastingPeace method, and makeLastingPeace, in turn, sends a negotiate message to the same Low object. If source code calls this object self,
- makeLastingPeace
{
[self negotiate];
…
}
the messaging routine finds the version of negotiate defined in Low, self’s class. However, if Mid’s source code calls this object super,
- makeLastingPeace
{
[super negotiate];
…
}
the messaging routine will find the version of negotiate defined in High. It ignores the receiving object’s class (Low) and skips to the superclass of Mid, since Mid is where makeLastingPeace is defined. Neither message finds Mid’s version of negotiate.
As this example illustrates, super provides a way to bypass a method that overrides another method. Here it enabled makeLastingPeace to avoid the Mid version of negotiate that redefined the original High version.
Not being able to reach Mid’s version of negotiate may seem like a flaw, but, under the circumstances, it’s right to avoid it:
The author of the Low class intentionally overrode Mid’s version of negotiate so that instances of the Low class (and its subclasses) would invoke the redefined version of the method instead. The designer of Low didn’t want Low objects to perform the inherited method.
In sending the message to super, the author of Mid’s makeLastingPeace method intentionally skipped over Mid’s version of negotiate (and over any versions that might be defined in classes like Low that inherit from Mid) to perform the version defined in the High class. Mid’s designer wanted to use the High version of negotiate and no other.
Mid’s version of negotiate could still be used, but it would take a direct message to a Mid instance to do it.
Using super
Messages to super allow method implementations to be distributed over more than one class. You can override an existing method to modify or add to it, and still incorporate the original method in the modification:
- negotiate
{
…
return [super negotiate];
}
For some tasks, each class in the inheritance hierarchy can implement a method that does part of the job and passes the message on to super for the rest. The init method, which initializes a newly allocated instance, is designed to work like this. Each init method has responsibility for initializing the instance variables defined in its class. But before doing so, it sends an init message to super to have the classes it inherits from initialize their instance variables. Each version of init follows this procedure, so classes initialize their instance variables in the order of inheritance:
- (id)init
{
if (self = [super init]) {
…
}
}
Initializer methods have some additional constraints, and are described in more detail in “Allocating and Initializing Objects.”
It’s also possible to concentrate core functionality in one method defined in a superclass, and have subclasses incorporate the method through messages to super. For example, every class method that creates an instance must allocate storage for the new object and initialize its isa variable to the class structure. This is typically left to the alloc and allocWithZone: methods defined in the NSObject class. If another class overrides these methods (a rare case), it can still get the basic functionality by sending a message to super.
Redefining self
super is simply a flag to the compiler telling it where to begin searching for the method to perform; it’s used only as the receiver of a message. But self is a variable name that can be used in any number of ways, even assigned a new value.
There’s a tendency to do just that in definitions of class methods. Class methods are often concerned not with the class object, but with instances of the class. For example, many class methods combine allocation and initialization of an instance, often setting up instance variable values at the same time. In such a method, it might be tempting to send messages to the newly allocated instance and to call the instance self, just as in an instance method. But that would be an error. self and super both refer to the receiving object—the object that gets a message telling it to perform the method. Inside an instance method, self refers to the instance; but inside a class method, self refers to the class object. This is an example of what not to do:
+ (Rectangle *)rectangleOfColor:(NSColor *) color
{
self = [[Rectangle alloc] init]; // BAD
[self setColor:color];
return [self autorelease];
}
To avoid confusion, it’s usually better to use a variable other than self to refer to an instance inside a class method:
+ (id)rectangleOfColor:(NSColor *)color
{
id newInstance = [[Rectangle alloc] init]; // GOOD
[newInstance setColor:color];
return [newInstance autorelease];
}
In fact, rather than sending the alloc message to the class in a class method, it’s often better to send alloc to self. This way, if the class is subclassed, and the rectangleOfColor: message is received by a subclass, the instance returned will be the same type as the subclass (for example, the array method of NSArray is inherited by NSMutableArray).
+ (id)rectangleOfColor:(NSColor *)color
{
id newInstance = [[self alloc] init]; // EXCELLENT
[newInstance setColor:color];
return [newInstance autorelease];
}
See “Allocating and Initializing Objects” for more information about object allocation.
Messages
Message expressions are enclosed in square brackets:
[receiver message]
The receiver can be:
A variable or expression that evaluates to an object (including the variable self)
A class name (indicating the class object)
super (indicating an alternative search for the method implementation)
The message is the name of a method plus any arguments passed to it.
Defined Types
The principal types used in Objective-C are defined in objc/objc.h. They are:
TypeDefinitionidAn object (a pointer to its data structure).ClassA class object (a pointer to the class data structure).SELA selector, a compiler-assigned code that identifies a method name.IMPA pointer to a method implementation that returns an id.BOOLA Boolean value, either YES or NO.
Note that the type of BOOL is char.id : 새로운 개발에 더 이상 사용되지 않는다. garbage
In Objective-C, object identifiers are a distinct data type: id. This is the general type for any kind of object regardless of class. (It can be used for both instances of a class and class objects themselves.) id is defined as pointer to an object data structure:
typedef struct objc_object {
Class isa;
} *id;
All objects thus have an isa variable that tells them of what class they are an instance.
Terminology: Since the Class type is itself defined as a pointer:
typedef struct objc_class *Class;
the isa variable is frequently referred to as the “isa pointer.”
Like a C function or an array, an object is therefore identified by its address. All objects, regardless of their instance variables or methods, are of type id.
id anObject;
For the object-oriented constructs of Objective-C, such as method return values, id replaces int as the default data type. (For strictly C constructs, such as function return values, int remains the default type.)
The keyword nil is defined as a null object, an id with a value of 0. id, nil, and the other basic types of Objective-C are defined in the header file objc/objc.h.
Method Declarations
The following conventions are used in method declarations:
A “+” precedes declarations of class methods.
A “-” precedes declarations of instance methods.
Argument and return types are declared using the C syntax for type casting.
Arguments are declared after colons (:), for example:
- (void)setWidth:(int)newWidth height:(int)newHeight
Typically, a label describing the argument precedes the colon—the following example is valid but is considered bad style:
- (void)setWidthAndHeight:(int)newWidth
int)newHeight
Both labels and colons are considered part of the method name.
The default return and argument type for methods is id, not int as it is for functions. (However, the modifier unsigned when used without a following type always means unsigned int.)
프로퍼티 설명
선언 프로퍼티
Objective-C 2.0의 또 다른 중요한 새 기능은 선언 프로퍼티를 지원한다는 것입니다. 객체 지향 프로그래밍에서 프로퍼티란 인스턴스 변수를 통해 직접 접근하는 대신 메쏘드를 통해 접근해야 하는 오브젝트로 둘러싸인 데이터를 의미합니다. 프로퍼티를 이용하면, 프로퍼티를 사용하는 다른 오브젝트의 실행에 영향을 미치지 않고 나중에 오브젝트 실행을 변경할 수 있습니다.
프로퍼티의 사용을 지원하고 장려하기 위한 방법으로, Objective-C 2.0은 최소한의 코드로 여러분의 클래스에 프로퍼티를 추가할 수 있는 선언 프로퍼티 신택스를 도입하였습니다. 반복적이고 오류가 많은 보일러플레이트 코드를 제공하는 대신, 여러분의 의도를 전달할 수 있는 간편한 선언 집합을 사용할 수 있습니다. 컴파일러는 이 선언을 이용하여 여러분의 클래스 인터페이스를 만족시키는데 필요한 접근자 메소드를 자동으로 생성합니다. 예를 들어, 클래스에 간단한 프로퍼티를 추가하려면 클래스 헤더에 다음과 같은 신택스를 사용할 수 있습니다.
@interface Person : NSObject {
NSString *location;
}
@property NSString *location;
@end
이 코드는 Person 클래스가 읽고 설정할 수 있는 location이라는 이름의 프로퍼티를 가지고 있음을 말해 줍니다. 클래스 실행 부분에 다음과 같은 코드를 추가하여 이 프로퍼티의 실행을 마무리할 수 있습니다.
@implementation Person
@synthesize location;
@end
이 코드는 컴파일러가 접근자 메쏘드를 생성, 합성할 수 있다는 것을 의미합니다. 컴파일러는 멀티코어 및 멀티쓰레드 환경에 맞는 빠른 알고리즘을 이용하여 설정자 메쏘드의 락킹 변수를 포함한 접근자 메쏘드를 생성합니다. 프로퍼티를 사용하는 것은 작성해야 할 코드의 양을 줄이는 것 뿐이 아니라, 현대의 멀티코어 시스템에 가장 적합한 접근자로 바꿔줍니다. 나중에 프로퍼티 액세서 대신 다른 실행 코드를 제공할 필요가 있으면, 클래스에 적절한 코드를 추가하기만 하면 됩니다.
프로퍼티에 접근하기
여러분의 코드에서 오브젝트의 프로퍼티를 사용하려면, 구조 엘리먼트에 접근할 때 사용하던 것과 동일한 패턴을 따르느 Objective-C 2.0의 새로운 닷 신택스를 사용할 수 있습니다. 예를 들어, 위에서 사용한 Person 클래스의 위치를 설정하려면 다음과 같은 코드를 사용하면 됩니다.
Person *bill = [[Person alloc] init];
bill.location = @”Home”
다음과 같은 코드로 프로퍼티에 접근할 수 있습니다.
NSLog(@”Bill’s location: %@”, bill.location);
Objective-C 2.0의 새로운 닷 신택스는 컴파일 시점에 접근자 메쏘드의 호출로 번역되어 컴파일러에게 보내는 신택스 메시지입니다. 예를 들어, 위 코드는 다음과 같은 메쏘드 호출과 동일한 역할을 합니다.
Person *bill = [[Person alloc] init];
[bill setLocation:@"Home"];
NSLog(@”Bill’s location: %@”, [bill location]);
이 중 어떤 접근자 메쏘드를 사용해도 프로퍼티 실행을 나중에 변경시킬 수 있는 기능을 유지할 수 있습니다.
프로퍼티 선언 속성
프로퍼티를 선언할 때, 기본적으로 컴파일러는 프로퍼티를 읽기/쓰기 프로퍼티로 처리하는 코드를 생성하고, setter에서 간단한 어싸인먼트를 사용합니다. 프로퍼티가 다른 비헤이비어를 가져야 할 경우에는 프로퍼티 선언 속성 세트를 사용할 수 있습니다. 예를 들어, 오브젝트의 복사본을 이용하여 어싸인먼트하여야 할 경우에는 프로퍼티를 다음과 같이 선언하면 됩니다.
@property(copy) NSString *location;
프로퍼티를 읽기 전용으로 규정하고 셋 액세서 메쏘드를 생성하지 않으려면 다음과 같이 사용하면 됩니다.
@property(readonly) int age;
프로퍼티의 get과 set 액세서 메쏘드의 이름을 규정하는 다른 프로퍼티 선언 속성도 있습니다. 프로퍼티 액세서 메쏘드가 non-atmic이어야 하는지를 알려주는 메쏘드 등 여러 가지가 있습니다.
빠른 Enumeration
Objective-C 2.0의 새로운 기능 중 마지막으로 소개할 것은 빠른 Enumeration, 즉, Objective-C 신택스 추가로 콜렉션의 모든 멤버를 단순하고 쉽게 운영할 수 있게 해 줍니다. 빠른 enumeration을 사용하면 코드가 더욱 명확해져 이해하기 쉽습니다. 예를 들어, 스트링 어레이를 이터레이션하려면 다음과 같은 코드를 사용하면 됩니다.
NSArray *array =
[NSArray arrayWithObjects:@"1", @"2", @"3", nil];
for (NSString *string in array) {
NSLog(@”string is %@”, string);
}
빠른 enumeration은 더욱 간편한 신택스를 제공하고, 안전한 enumeration을 제공한다는 면에서, NSEnumerator 오브젝트를 직접 사용하는 것에 비해 상당히 효율적입니다. enumeration 과정 중 콜렉션을 변경하면, 예외가 발생합니다. enumeration 중 콜렉션의 변경은 허용되지 않기 때문에, 다중 쓰레드 상에서 여러번의 enumeration을 동시에 수행할 수 있습니다.
빠른 enumeration은 NSFastEnumeration 프로토콜을 실행하는 모든 콜렉션에서 가능합니다. NSArray, NSDictionary, NSSet, NSEumerator를 포함한 모든 Cocoa 콜렉션 클래스는 이 프로코톨을 실행합니다. 또한, 단일 메쏘드로 구성된 NSFastEnumeration 프로토콜 지원을 이용하여 여러분의 콜렉션에 빠른 enumeration을 추가할 수 있습니다.
The objc_msgSend Function
In Objective-C, messages aren’t bound to method implementations until runtime. The compiler converts a message expression,
[receiver message]
into a call on a messaging function, objc_msgSend. This function takes the receiver and the name of the method mentioned in the message—that is, the method selector—as its two principal parameters:
objc_msgSend(receiver, selector)
Any arguments passed in the message are also handed to objc_msgSend:
objc_msgSend(receiver, selector, arg1, arg2, …)
위에서 너무 자세히 설명하셔서 기술적인 내용을 안 하겠습니다.
이해하기 쉽게 예를 들어보겠습니다.
클래스를 붕어빵을 만드는 기계라고 생각해보세요.
인스턴스는 붕어빵 기계로 만든 “붕어빵”입니다.
클래스가 개념적인 형태라면 인스턴스는 실체입니다.
예) SampleClass sc = new SampleClass();
위에서 SampleClass 는 클래스이고, sc는 인스턴스이고 여기서는 new는 클래스에서
인스턴스를 만드는 생성자 함수입니다.