Tuesday, July 2, 2013

iOS: Ngôn ngữ lập trình Objective C - P3



1.1.                     Quản lý bộ nhớ

1.1.1.     Các nguyên tắc quản lý bộ nhớ

Nguyên tắc cơ bản
·        Khi bạn nắm quyền sở hữu một đối tượng, khởi tạo đối tượng bằng các phương thức mà trong tên bắt đầu với với alloc hoặc new hoặc copy (ví dụ, alloc, newObject hoặc mutableCopy…) hoặc gửi một thông điệp retain, bạn phải có trách nhiệm giải phóng quyền sở hữu đối tượng đó bằng cách sử dụng release hoặc autorelease. Bất kỳ khi nào bạn nhận được một đối tượng (không phải tự mình khởi tạo), bạn không được release nó.

Các nguyên tắc khác
·        Khi bạn cần lưu trữ một đối tượng được nhận như một propertytrong một biến thể hiện, bạn phải retain hoặc copy nó. (Điều này không đúng cho cho tham khảo yếu, nhưng đây là điển hình hiếm).
·        Một đối tượng được nhận thường đảm bảo vẫn có hiệu lực trong phương thức mà nó đã được nhận (ngoại trừ trong các ứng đa luồng và vài trường hợp Distributes Objects). Phương thức đó có thể trả về an toàn đối tượng mà nó được triệu gọi. Sử dụng retain trong việc kết hợp với release hoặc autorelease khi cần thiết để bảo vệ một đối tượng khỏi hiệu lực của các thông điệp không hợp lệ bên ngoài.
·        autoreleasecó nghĩa là “gửi một thông điệp releasesau đó


1.1.2.     Vấn đề khi khởi tạo đối tượng

Xét đoạn code khởi tạo đối tượng sau

  TestClass *ptr = [TestClass alloc];
  [ptr init];

  // Do something with the object
  if (ptr)
    ...
Thoạt nhìn qua có vẻ vô hại, phương thức alloc khởi tạo một vùng nhớ cho đối tượng ptr, sau đó gửi thông điệp gọi phương thức init cho đối tượng ptr, lỗi có thể xảy ra ở đây. Giả sử dòng lệnh ở dòng lệnh [ptr init], phương thức init có lỗi xảy ra và trả về nil, tiếp theo ở dòng lệnh if, lúc này ptr vẫn khác nil mặc dù phương thức inittrả về nil (nhưng nó không được gán cho ptr), dẫn tới ý nghĩa của phương thức tạo thực sự không còn nữa.

Khi đó, đoạn code sau sẽ giải quyết được khả năng lỗi ở trên

  TestClass *ptr = [[TestClass alloc] init];

  // Do something with the object
  if (ptr)
    ...

Giả sử initcó lỗi và trả về nilthì ptr vẫn sẽ được gán là nil, do đó dòng lệnh ifsẽ thực hiện đúng ý nghĩa của nó.
Ý nghĩa từ ví dụ này đó là, ta luôn luôn phải trả về nil trong phương thức initnếu có lỗi khởi tạo xảy ra và lưu ý phải kết hợp 2 lời gọi phương thức allocinit.

1.1.3.     Release

Nếu bạn khởi tạo một đối tượng sử dụng cách thủ công alloc, bạn cần phải release đối tượng sau đó. Bạn không nên thực hiện release thủ công một đối tượng autorealse bởi vì ứng dụng có thể sẽ bị crash nếu bạn làm điều đó.

            // string1 will be released automatically
          NSString* string1 = [NSString string];

          // must release this when done
          NSString* string2 = [[NSString alloc] init];
          …..
          [string2 release];

1.1.4.     Retain


Trong Objective-C, mỗi đối tượng có một bộ đếm được sử dụng để kiểm soát tất cả các tham chiếu bởi đối tượng hoặc nó có.
Để biết được giá trị của bộ đếm này ta sử dụng thuộc tính retainCount [object retainCount]. Phương thức alloc, new, copyretain đều tăng bộ đếm này lên 1 và phương thức release giảm bộ đếm này đi 1, khi bộ đếm có giá trị bằng 0 thì phương thức dealloc của đối tượng sẽ được gọi.



Bất cứ khi nào một đối tượng có nhu cầu được sử dụng bởi một đối tượng khác nó phải retain để tăng bộ đếm retainCount lên 1, và khi nó không còn sử dụng nữa thì phải release để giảm bộ đếm retainCount đi 1. Khi bộ đếm có giá trị bằng 0 có nghĩa là nó không còn nhu cầu để sử dụng nữa, nó sẽ tự hủy bằng phương thức dealloc.

1.1.5.      Dealloc

Phương thức dealloc được gọi khi đối tượng đang được remove khỏi bộ nhớ. Nó thường được sử dụng nhất khi giải phóng tất cả các tham chiếu của các biến thể hiện con của đối tượng khỏi bộ nhớ. Hay nói cách khác, một lớp nếu có các biến thể hiện là các đối tượng thì trong phương thức dealloc của lớp phải thực hiện giải phóng các biến thể hiện này.

- (void)dealloc {
          [childVar1 release];
          [childVar2 release];
          [super dealloc];
}
Phương thức [super dealloc] được sử dụng để thông báo cho lớp cha thực hiện việc “dọn dẹp” (đây là phương thức được định nghĩa trong NSObject), nếu không gọi phương thức này, có thể đối tượng sẽ không được remove khỏi bộ nhớ, sẽ gây nên tình trạng chiếm bộ nhớ.

#import
#import "Address.h"

@interface Person : NSObject {
          Address* address;
}
-(Person*) constructor: (Address*) add;
-(void) show;
@end

#import "Person.h"

@implementation Person
-(Person*) constructor: (Address*) add{
          self = [super init];
          if(self){
                   address = add;
          }
          return self;
}
-(void) show{
          printf("Person: \n");
          printf("   --- ");
          [address show];
}
-(void) dealloc{
          printf("Dealloc method of Person\n");
          [address release];
          [super dealloc];
}
@end


#import
#import "Person.h"
#import "Name.h"

@interface VNPerson : Person {
          Name* name;
}
-(VNPerson*) constructor: (Address*) add : (int) idn;
@end

#import "VNPerson.h"
#import "Name.h"

@implementation VNPerson

-(VNPerson*) constructor: (Address*) add : (int) idn{
          self = [super constructor: add];
          if(self){
                   name = [[Name alloc] constructor: idn];
          }
          return self;
}
-(void) show{
          [super show];
          printf("   --- ");
          [name show];
}
-(void) dealloc{
          printf("Dealloc method of VNPerson\n");
          [name release];
          [super dealloc];// Mục đích giải phóng biến thể hiện address trong lớp cha
}
@end


#import "Address.h"
#import "VietnamAddress.h"
#import "Person.h"
#import "VNPerson.h"

int main(int argc, char *argv[]) {
   
          Address *address = [[Address alloc] constructor: 01 : 02];
          [address show];
          VietnamAddress *vnaddress = [[VietnamAddress alloc] constructor: 03 : 04];
          [vnaddress show];
          [vnaddress changeAddress: 05];
         
          Person *person = [[VNPerson alloc] constructor: address : 1915];
          [person show];
         
          [address release];
          [vnaddress release];
          [person release];
                  
          return 1;
}

Lưu ý: Phương thức dealloc sẽ không được gọi trong trường hợp bộ dọn rác được bật.





1.1.6.     Tham chiếu yếu

Retain một đối tượng tạo ra một tham chiếu “mạnh” đến đối tượng đó. Một đối tượng không thể dealloc cho tới khi tất cả các tham chiếu mạng được giải phóng hết.

Trong một số trường hợp, ta có thể muốn có một tham chiếu đến đối tượng mà không cản trở việc đối tượng tự giải phóng chính nó, lúc này ta có thể thiết lập một tham chiếu “yếu” đến đối tượng.
Một tham chiếu yếu được tạo ra bằng cách chứa một con trỏ trỏ đến một đối tượng mà không retain đối tượng đó. Tham chiếu yếu rất cần thiết trong việc thiết lập các tham chiếu vòng. Ví dụ, đối tượng A và đối tượng B cần trao đổi thông tin với nhau nên mỗi đối tượng cần một tham chiếu đến đối tượng kia (ví như mới quan hệ giữa 2 đối tượng cha - con), nếu như chúng ta retain đối tượng kia khi thiết lập tham chiếu thì mỗi đối tượng chỉ được dealloc khi nào kết nối này đứt, tuy nhiên kết nối này chỉ đứt khi có một đối tượng được dealloc mà thôi. Trong trường hợp này ta thấy được lợi ích của tham chiếu yếu.
Chúng ta phải thật cẩn thận khi truyền thông điệp trong tham chiếu yếu, trong trường hợp đối tượng nhận thông điệp đã dealloc thì ứng dụng có thể sẽ bị crash. Đồng thời, trong mối quan hệ tham chiếu yếu, đối tượng được tham chiếu đến phải có trách nhiệm báo cho đối tượng kia biết khi nó thực hiện dealloc, ví dụ gửi một thông điệp setDelegate:với tham số nil cho đối tượng kia chẳng hạn, trong trường hợp đối tượng dealloc là một Delegate của đối tượng nhận thông điệp.

iOS: Ngôn ngữ lập trình Objective C - P2



1.1.                     Lớp

1.1.1.     Các khái niệm cơ bản

1.1.1.1.          Định nghĩa lớp

Một lớp trong Objective-C được định nghĩa gồm 2 file thành phần tương tự C, C++. Một file *.h định nghĩa trước các biến thành phần và tên các phương thức, file *.m định nghĩa phần thực thi cho các phương thức trong file *.h

File ClassName.h

#import

@interface ClassName {
     variable1 declaration;
     variable2 declaration;
}
    method1 declaration;
    method2 declaration;
@end

Objective-C sử dụng từ khóa @interface để khai báo một tên lớp trong file h. Từ khóa @endđược sử dụng ở cuối phần khai báo.

File ClassName.m

#import "ClassName.h"

@implementation ClassName
   -method 1 //triển khai phương thức 1
   -method 2 // triển khai phương thức 2
@end

Objective-C sử dụng từ khóa @implementation để khai báo phần thực thi thực sự của lớp trong file m. Từ khóa @end được sử dụng ở cuối phần khai báo.


Ví dụ:
MyClass.h
@interface MyClass {
    int a;
    int b;
}
    -(void) setvara : (int) x;
    -(void) setvarb : (int) y;
    -(int) add;
@end

MyClass.m
#import"MyClass.h"

@implementation MyClass
   -(void) setvara :(int) x {
     a=x;
   }
   -(void) setvarb :(int) y {
     b=y;
   }
   -(int) add {
     return a+b;
   }
@end

1.1.1.2.          Thuộc tính

Cú pháp khai báo thuộc tính:
           
                        [Access Privilege] TypeName  varName;
Ví dụ
            @private
                   int  att1;
                   NSString str1;
          @protected
                   int att2;
          @public
                   NSString str2;
                   int att3;

Mặc định khi không sử dụng từ khóa quyền truy xuất là @protected

1.1.1.3.          Phương thức

Cú pháp định nghĩa một phương thức
            [Access Privilege](return_type) methodname: (type1) para1 : (type2) para2 (...);

Gọi phương thức
          [object methodname:para1 : para2…];
Ví dụ:
          Khai báo
          -(MyClass*) constructor: (int) a : (int) b;

          Triển khai
-(MyClass*) constructor: (int) a : (int) b {
          self = [super init];
          if(self) {
                var1 = a;
                var2 = b;
          }
          return self;
        }
}
Lời gọi phương thức như sau

[myClassObject constructor: 100 : 200];

Trong Objective-C chỉ có 2 khái niệm quyền truy xuất đến phương thức: truy xuất hoàn toàn qua lớp (public static) và truy xuất hoàn toàn qua đối tượng (public)
Objective-C qui định phần định nghĩa truy xuất như sau
  • Phương thức truy xuất thông qua tên lớp sẽ có ký hiệu là dấu +
  • Phương thức truy xuất thông qua đối tượng sẽ có ký hiệu là dấu –

@interface MyClass: NSObject
    -(MyClass*) staticMethod: (int) a : (int) b;
    -(MyClass*) publicMethod: (int) a : (int) b;
@end

Trong trường hợp phương thức có nhiều tham số, và để thể hiện được ý nghĩa của các tham số trong lời gọi phương thức, Objective-C cho phép một cú pháp khai báo khác cho phương thức như sau:

[Access Privlilege](return_type) methodPara1: (type) para1 andPara2: (type) para2;

Lời gọi phương thức khi đó sẽ như sau:

[object methodPara1: value1 andPara2: value2];

Ví dụ:
          -(void) setX: (int) x Y: (int) y;

-(void) setX: (int) x Y: (int) y {
   var1 = x;
   var2 = y;
}

[myObject setX: 15 Y: 20];



1.1.2.     Kế thừa

Tính kế thừa trong Objective-C tương tự trong các ngôn ngữ khác như C++,…

#import "SuperClass.h"
#import

@interface ClassName:SuperClass {
     variable1 declaration;
     variable2 declaration;
   }
    method1 declaration;
    method2 declaration;
@end

Ví dụ:

#import

@interface MyClass:NSObject {
    int a;
    int b;
  }
    -(void) setvara : (int) x;
    -(void) setvarb : (int) y;
    -(int) add;
@end

Trong Objective-C, thực sự tất cả các lớp khi tạo ra đều kế thừa từ lớp NSObject.

1.1.3.     Phương thức tạo

Trong Objective-C không có khái niệm phương thức tạo cho một lớp. Tất cả các đối tượng của một lớp phải được cấp phát thông qua phương thức allocinit.
MyClass *myObject = [[MyClass alloc]init];  
Trong đó phương thức alloc là cấp phát vùng nhớ, còn phương thức init như là một phương thức tạo mặc định trong Objective-C, được định nghĩa trong lớp NSObject.
-(id) init;

Ta thường định nghĩa lại phương thức tạo có tham số của một lớp như sau:

#import "SuperClass.h"
#import

@interface MyClass: NSObject {
     int var1;
     int var2;
   }
    -(MyClass*) constructor: (int) a : (int) b;
@end
                       
#import "MyClass.h"

@implementation MyClass
      -(MyClass*) constructor: (int) a : (int) b {
          self = [super init];
          if(self) {
                var1 = a;
                var2 = b;
          }
          return self;
        }
 @end
Từ khóa supercon trỏ trỏ đến lớp cha của lớp hiện tại, tương tự như base trong C++ hoặc super trong Java.
Từ khóa selflà con trỏ đại diện cho lớp hiện tại, tương tự con trỏ this trong C++ hay Java.

1.1.4.     Properties

Trong Objective-C hỗ trợ tính năng Properties, cho phép chúng ta định nghĩa các bộ truy xuất (setter/getter) vì vậy sẽ có nhiều lợi ích sử dụng khi truy xuất đến các biến thể hiện của đối tượng.

Định nghĩa trong file.h:   @property () type propertyName;
Thực thi trong file.m:      @synthesize propertyName;
            Truy xuất đến properties thông qua cú pháp object.property

#import /Foundation.h>


@interface Address : NSObject {
          int countryCode;
          int cityCode;
}
@property (readonly) int countryCode;
@property int cityCode;
...
@end

#import "Address.h"

@implementation Address
@synthesize countryCode;
@synthesize cityCode;
...
@end

Address *address = [[Address alloc] init];
Int code = address.countryCode;
address.cityCode = 99;

Các thuộc tính cho Properties
·        Writability
o   readwrite: chỉ ra Properties có thể đọc và ghi, thuộc tính này là mặc định
o   read-only: chỉ ra Properties chỉ có thể đọc.
·        Setter Semantics
o   assign: là thuộc tính mặc định. Ta thường sử dụng assign cho các kiểu vô hướng như NSInteger, CGRect…
Ta có thể hình dung như sau
@interface Test5 : NSObject {
        @private NSString *sVar;
}
@property (readwrite, assign) NSString *sVar;
@end
            Properties này tương tự như settor sau
-(void)setSVar:(NSString*)inSVar {
        if (self->sVar != inSVar){
                [self->sVar release];
                self->sVar = [inSVar retain];
        }
}

o   retain: retain nên được triệu gọi trên đối tượng được chỉ định.
o   copy: một bản sao của đối tượng sẽ được sử dụng cho đối tượng chỉ định.

Ta có thể hình dung như sau
@property (readwrite, copy) NSString *sVar;
            Properties này tương tự như settor sau

-(void)setSVar:(NSString*)inSVar {
        if (self->sVar != inSVar){
                [self->sVar release];
                self->sVar = [inSVar copy];
        }
}
Ta sử dụng chỉ định copy khi mà có khả năng tham số sVar là đối tượng có thể thay đổi
Những ràng buộc phụ thuộc vào việc bạn chọn sử dụng hoặc không sử dụng bộ thu gom rác
o   Nếu bạn không sử dụng bộ thu gom rác, với Properties của đối tượng bạn phải chỉ rõ assign, retain hay copy, nếu không trình biên dịch sẽ cảnh báo
o   Nếu bạn sử dụng bộ thu gom rác, bạn sẽ không bị cảnh báo nếu không chỉ định assign, retain hay copy (mặc định khi đó là assign), trừ khi kiểu của Properties là một lớp thích hợp với NSCopying. Để mặc định thường là những gì bạn muốn, tuy nhiên, nếu đối tượng có thể sao chép thì để bảo tồn tính bao đóng bạn thường muốn làm một bản sao chép riêng cho đối tượng.
o   Nếu bạn sử dụng bộ thu gom rác thì assignretain có hiệu lực như nhau
·        Atomicity: thuộc tính này chỉ ra Properties là không atomicity với từ khóa nonatomic. Việc này tương tự như đồng bộ hóa trong khái niệm Thread, Properties này sẽ bị block và thực hiện đồng bộ. Mặc định là atomic.

1.2.                     Category

Khi ta muốn thêm một số phương thức vào một lớp có sẵn, thông thường ta sẽ mở rộng lớp đó bằng cách viết lại mã nguồn. Objective-C cung cấp tính năng Category cho phép ta mở rộng lớp mà không cần phải viết lại mã nguồn của lớp cũ. Category cho phép ta mở rộng lớp cũ trong một bộ thực thi khác.
Giả sử ta có một lớp MyClass đã định nghĩa

MyClass.h
@interface MyClass
-(void) print;
@end

MyClass.m
#import "MyClass.h"
@implementation MyClass
-(void) print {
//to do print
}

Ta muốn thêm một một phương thức newMethod, ta sử dụng tính năng Category của Objective-C như sau

MyCategory.h

#import "MyClass.h"
@interface MyClass (MyNewCategory)
-(void) newMethod;
@end
MyCategory.m

#import "MyCategory.h"
@implementation MyClass (MyNewCategory)
-(void) newMethod {
  //to do new method
}




Sử dụng như sau
#import "MyClass.h"
#import "MyCategory.h"

int main(int argc, const char *argv) {
          MyClass *myObject = [[MyClass alloc] init];
          [myObject print];
          [myObject newMethod];
}

·        Tên của Category là duy nhất, có thể thêm nhiều Category nhưng không được trùng tên.
·        Trong Category không cho phép thêm các biến thể hiện
Ngoài mục đích  mở rộng, Category thường được sử dụng để “định nghĩa” các phương thức “private” (không được hỗ trợ trong Objective-C)

// ===========================
// = File: SomeClass.m
// ===========================
#import "SomeClass.h"

// =================================
// = Interface for hidden methods
// =================================
@interface SomeClass (hidden)

+(void) hiddenClassMethod;
-(void) hiddenInstanceMethod;

@end

// =====================================
// = Implementation of hidden methods
// =====================================
@implementation SomeClass (hidden)

+(void) hiddenClassMethod {
  printf( "Hidden class method.\n" );
}

-(void) hiddenInstanceMethod {
  printf( "Hidden instance method\n" );
}

@end

// ================================
// = Implementation for SomeClass
// ================================
@implementation SomeClass

-(void) msg {
  printf("Inside msg()...\n");

  [self hiddenInstanceMethod];
  [SomeClass hiddenClassMethod];
}

+(void) classMsg {
  printf("Inside classMsg()...\n");
}

@end

Khi đó, ta sử dụng lớp SomeClass với phương thức msg() mà không biết đến các phương thức “hidden” như là các phương thức private

// ===========================
// = File: Main.m
// ===========================
#import "SomeClass.h"

int main (int argc, char *argv[]){
  SomeClass *ptr = [[SomeClass alloc] init];

  // Display message (including messages from hidden methods)
  [ptr msg];

  // Call a class method
  [SomeClass classMsg];

  return 0;
}

1.3.                     Posing

Pose là một tính năng của Objective-C cho phép lớp con thay thế (pose – in place of) lớp cha mà nó kế thừa trong một ngữ cảnh nhất định.

@interface Fraction
-(void) print;
@end

#import "Fraction.h"

@implementation Fraction
-(void) print {
    printf( "printf of Fraction");
}
@end


#import "Fraction.h"
@interface FractionA : Fraction
-(void) print;
@end

#import "FractionA.h"

@implementation FractionA
-(void) print {
    printf( "new printf of FractionA");
}
@end


#import "Fraction.h"
#import "FractionB.h"

int main( int argc, const char *argv[] ) {
    Fraction *frac = [[Fraction alloc] init];

    // print it
    printf( "The fraction is: " );
    [frac print];
    printf( "\n" );

    // FractionA pose as Fraction
    [FractionA poseAsClass: [Fraction class]];

    Fraction *frac2 = [[Fraction alloc] init];

    // print it
    printf( "The fraction is: " );
    [frac2 print];
    printf( "\n" );

    // free memory
    [frac release];
    [frac2 release];

    return 0;
}

Kết quả là

The fraction is: printf of Fraction
The fraction is: new printf of FractionA

Phương thức poseAsClass là một phần của protocol NSObject

1.4.                     Protocol

Protocol định nghĩa một danh sách các phương thức bắt buộc hoặc tùy chọn mà các lớp chấp nhận (adopt) protocol bắt buộc phải thực thi.

@protocol MyProtocol

- (void)requiredMethod;

@optional

- (void)anOptionalMethod;

- (void)anotherOptionalMethod;

@required

- (void)anotherRequiredMethod;

 @end
Các phương thức khai báo trong Protocol cũng có thể là các khai báo Properties. Các từ khóa @optional@requiredthể hiện theo đúng ý nghĩa của nó, nếu không sử dụng 2 từ khóa này thì mặc định là @required.

@protocol NSCoding
- (void)encodeWithCoder:(NSCoder *)aCoder;
- (id)initWithCoder:(NSCoder *)aDecoder;
@end

// Interface
@interface SomeClass : NSObject {
  ...
}

// Implementation
@implementation SomeClass

-(void)encodeWithCoder:(NSCoder *)aCoder{
  ...
}

-(id)initWithCoder:(NSCoder *)aDecoder{
  ...
}
SomeClass triển khai Protocol NSCoding theo cú pháp
@interface ClassName : ItsSuperclass < protocol list >
@interface ClassName ( CategoryName ) < protocol list >
Ví dụ:
@interface Formatter : NSObject < Formatting, Prettifying >

Protocol được sử dụng trong các trường hợp:
-         Khai báo các phương thức dự kiến sẽ được thực thi
-         Khai báo một interface cho một đối tượng trong khi ẩn đi lớp của nó
-         Khảo sát tương đồng giữa các lớp mà không phải liên quan đến cấu trúc thứ bậc




1.1.                     Association References

Sử dụng tham chiếu liên kết để giả lập việc bổ sung các biến thể hiện đối tượng vào một đối tượng khác.
Việc khởi tạo một tham chiếu liên kết chủ yếu dựa trên một key, ta có thể thêm nhiều liên kết nếu ta muốn với nhiều key khác nhau, sử dụng hàm runtime của Objective-C là objc_setAssociatedObject

void objc_setAssociatedObject (id object, void *key, id value, objc_AssociationPolicy policy)

object: đối tượng nguồn của liên kết
key: khóa của liên kết. Khóa này thường là đối tượng static.
value: giá trị liên kết với khóa cho đối tượng. Đưa giá trị nil để xóa một liên kết đã tồn tại
policy: các policy cho liên kết

static char overviewKey;

 NSArray *array = [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil];

NSString *overview = [[NSString alloc] initWithFormat:@"%@", @"First three numbers"];

objc_setAssociatedObject(array, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN);

Tạo liên kết overview vào đối tượng array, ta truy xuất đối tượng liên kết overview thông qua đối tượng array và khóa
NSString *associatedObject = (NSString *)objc_getAssociatedObject(array, &overviewKey);

1.2.                     Selector

Trong Objective-C, khái niệm Selector có 2 nghĩa. Nó có thể được dùng đơn giản là chỉ đến tên của một phương thức khi nó được sử dụng trong mã nguồn một thông điệp gửi đến một đối tượng. Bên cạnh đó nó còn chỉ đến một định danh duy nhất mà thay thế cho một tên khi mã nguồn được biên dịch
Selector khi được biên dịch có kiểu là SEL. Tất cả các phương thức có cùng tên thì có cùng selector. Ta có thể sử dụng một selector để triệu gọi một phương thức trên một đối tượng, điều này thể hiện khá căn bản mẫu thiết kế target-action trong Cocoa.

SEL setWidthHeight;
setWidthHeight = @selector(setWidth:Height:);

Chỉ thị @selectorcho phép ta tham chiếu đến một selector được biên dịch hơn là tên một phương thức đầy đủ. Đoạn mã trên là một selector cho phương thức setWidth:Heightđược assign cho biến SELsetWidthHeight.
Ở trên trường hợp ta tham chiếu đến một selector thông qua chỉ thị @selector, trong một số trường hợp ta có thể chuyển từ một chuỗi ký tự thành một selector trong thời điểm runtime bằng phương thức NSSelectorFromString.

setWidthHeight = NSSelectorFromString(aBuffer);

Và ngược lại ta có thể lấy tên phương thức từ một selector thông qua phương thức NSStringFromSelector.

NSString *method;
method = NSStringFromSelector(setWidthHeight);

Một selector đã biên dịch chị định một tên phương thức chứ không thực thi phương thức. Ví dụ, có một phương thức Display cho một lớp, có nhiều selector giống nhau cho phương thức Display ở các lớp khác, với mục đích đa hình và ràng buộc động. Nếu có một selector cho mỗi phương thức thực thi, thì một thông điệp sẽ không khác một lời gọi phương thức.

Một phương thức lớp và một phương thức thể hiện có cùng tên được assign bởi một selector. Tuy nhiên, bởi vì 2 phương thức này phân biệt domain (phạm vi lớp, phạm vi đối tượng của lớp) nên sẽ không có sự nhầm lẫn giữa 2 phương thức này.

Việc định tuyến một thông điệp truy xuất vào một phương thức chỉ thông qua một selector duy nhất, vì vậy nó đối xử như nhau đối với các phương thức có cùng selecor. Nó phát hiện kiểu trả về của phương thức và kiểu dữ liệu của các tham số thông qua selector. Vì vậy, ngoại trừ thông điệp truyền vào các bộ nhận kiểu tĩnh, còn lại với các ràng buộc động nó yêu cầu tất cả các tên phương thức thực thi phải có cùng kiểu trả về và có tham số cùng kiểu. (các bộ nhận kiểu tĩnh là ngoại lệ, trình biên dịch có thể biết về các phương thức thực thi từ kiểu lớp).

Mặc dù định danh của phương thức lớp và phương thức thể hiện là cùng một selector, nhưng chúng có thể có kiểu trả về và kiểu của các tham số khác nhau.


Ba phương thức performSelector:, performSelector:withObject:, và performSelector:withObject:withObject:, định nghĩa trong protocol NSObject lấy các định danh SEL như là các tham số khởi tạo. Tất cả các phương thức này ánh xạ trực tiếp vào thông điệp phương thức. Ví dụ:

[friend performSelector:@selector(gossipAbout:) withObject:aNeighbor];

Tương đương với

[friend gossipAbout:aNeighbor];

Hoặc ví dụ:

id   helper = getTheReceiver();

SEL  request = getTheSelector();

[helper performSelector:request];

Các phương thức có thể biến đổi tại thời điểm runtime, như ở trên bộ nhận helper được chọn thông qua phương thức getTheReceivervà bộ nhận này được yêu cầu thực hiện phương thức request thông qua phương thức getTheSelector tại thời điểm runtime.

Lưu ý, khi một bộ nhận buộc phải thực hiện một phương thức mà không thuộc phạm vi của mình thông qua selector thì đương nhiên sẽ xuất hiện lỗi. Vì những công việc này thực thi ở thời điểm runtime nên hiển nhiên lỗi sẽ chỉ xuất hiện tại thời điểm chương trình được thực thi.



1.3.                     Xử lý ngoại lệ


@try {
    ...
}
@catch (CustomException *ce) {  // 1
    ...
}
@catch (NSException *ne) {  // 2
    // Perform processing necessary at this level.
   ...
}
@catch (id ue) {
   ...
}
@finally {  // 3

    // Perform processing necessary whether an exception occurred  or not.
    ...
}

·        Bắt các kiểu ngoại lệ cụ thể nhất
·        Bắt các kiểu ngoại lệ chung

1.4.                     Threading

Objective-C hỗ trợ đa luồng trong ứng dụng. Tìm hiểu lớp NSThread trong Foundation Framework của Objective-C để hiểu chi tiết về cách sử dụng Thread
Để sử dụng tính đồng bộ trong việc các luồng truy xuất đến một vùng dữ liệu hoặc phương thức, Objective-C sử dụng chỉ thị @synchronized()

- (void)criticalMethod{
    @synchronized(self) {
        // Critical code.
        ...
    }
}

1.5.                     Thông điệp từ xa

Objective-C hỗ trợ việc truyền thông điệp từ xa, như Webservice, chúng ta sẽ tìm hiểu phần này trong giai đoạn tìm hiểu Foundation Framework của Objective-C.