Khái niệm chung về Object C

I. Thông tin chung:

– Lập trình IOS cần phải biết về ngôn ngữ C Object. Vì C Object là ngôn ngữ chính của Apple trong việc phát triển các chương trình trong Mac OS (IOS lẫn Mac OS). Đây là ngôn ngữ chính thức để lập trình với Apple.

– Dĩ nhiên bạn có thể dùng các ngôn ngữ khác để lập trình;

+ PHP: Ngôn ngữ đánh dấu văn bản có thể được sử dụng để viết chương trình với IOS nhưng nó có những hạn chế riêng

+ C# với Mono Touch, bạn có thể chuyển ngôn ngữ sang để lập trình với IOS nhưng nó không phải là chính thức mà thông qua một hãng thứ ba (không phải là Apple cho chính thức phát hành).

+ Lua (ngôn ngữ lập trình Script) với Codea lập trình hoàn toàn trên Ipad. Có một số dự án đã hoàn thành như (Cargo Bot, …) tiện lợi nhưng không trực quan, và cách để có được chương trình trên Apple tương đối phức tạp (Export).

+ Ngoài ra vẫn có thể sử dụng C và C++ để lập trình Iphone

+ Java cũng có thể lập trình Iphone được

+ Một số ngôn ngữ khác nhưng tôi không biết

=> C Object vẫn là ưu tiên hàng đầu khi lập trình Iphone/Ipad vì đây là ngôn ngữ chính được hỗ trợ bởi chính Apple
=> Object C không hể dựa trên C++ như nhiều người lầm tưởng vì chúng ra đời trong cùng một năm (1983)

II. Nội dung chính:

Tuy là học về Object C nhưng sự khác nhau về mục đích sẽ làm cách học khác nhau ví dụ bạn học Object C để viết phần mềm cho Mac nó khác khi viết cho IOS. Sự phát triển của các công cụ hỗ trợ IDE rất nhanh, có những thứ thật sự bạn không cần phải quan tâm nữa.

Đối với các lập trình viên C, việc quản lý bộ nhớ là vô cùng quan trọng, bộ nhớ của các thiết bị di động lúc trước là rất nhỏ, tiết kiệm được chút bộ nhớ sẽ làm chương trình chạy mượt mà hơn. Tuy nhiên hiện tại thì việc đó không còn cần thiết nữa do IDE mới đã tích hợp bộ ARC (Automatic Release Control) giúp cho các lập trình viên không cần phải quan tâm nhiều đến việc quản lý bộ nhớ. ARC đã loại bỏ hẳn việc release bộ nhớ.

Như vậy bạn phải hiểu rằng, công nghệ thông tin có những thay đổi vượt bậc và việc làm theo những cách cũ hay hiểu biết những thứ như vậy chả giúp ích gì cho việc lập trình nó chỉ làm cho bạn vất vả thêm, chương trình ra chậm hơn.

1. Đặc điểm cơ bản:

– Là ngôn ngữ hướng đối tượng

– Mở rộng từ C

– Nhẹ nhàng (không sử dụng VM – không quá thực tạp với friend virtuals với template với….)

– Mềm dẻo (mở rộng từ C nên bạn có thể dùng C thuần cấu trúc ngoài ra đây là ngôn ngữ run-time)

– Reflection (có hỗ trợ)

– nil thay thế cho NULL trong C, bởi vì bạn có thể gửi thông điệp cho nil, nhưng không thể làm như vậy với NULL.

– BOOL có 2 giá trị là YES và NO chứ không phải là true và false nữa.

– Khái niệm methods và message đc sử dụng mang ý nghĩa như nhau đối với ObC theo đó message có những thuộc tính đặc biệt. Mọto message có thể chuyền động từ obj tới một obj khác. Việc gọi thông điệp trên một obj không có nghĩa là obj đó sẽ thực hiện message nó có thể chuyển tiếp tới một obj khác chưa biết trước tóm lại có khả năng đáp trả thông điệp không trực tiệp thì gián tiếp.

Khi làm việc với Objective C bạn cần chú ý là bởi vì nó đượcc base trên nền của C cho nên việc bạn sử dụng cú pháp C chộn lẫn với cú pháp chính thống của Objective C là hoàn toàn chấp nhận, tuy nhìn có vẻ hơi củ chuối.

Phương thức:

1. Enum trong lập trình C Object

typedef enum {

   Monday=1,

   …

} WORKDAYS;

WORKDAYS today = Monday;

=> Cách sử dụng enum trong lập trình C Object

2. Cách khai báo phương thức trong Objective C
Không tham số :

<(kiểu trả về)> Tên phương thức

* Ví dụ: -(void) print;

Có tham số:
<(kiểu trả về)> Tên_phương_thức :<(kiểu)> Tên_Biến :<(kiểu)> Tên_Biến;
* Ví dụ:

-(void) setDenominator: (int) d;
Lời gọi phương thức:
không trả về: [<đối tượng> ];
[<đối tượng> :<(kiểu)> ];
[<đối tượng> :<(kiểu)> :<(kiểu)> ];
Trả về kết quả: = [<đối tượng> ];
= [<đối tượng> :<(kiểu)> :<(kiểu)> ];

3.Categories:

Là đặc điểm nếu bạn muốn mở rộng lớp bằng cách thêm mới vào lớp một phương thức. Khi bạn làm việc quen với OOP thì bạn sẽ thấy đây là một trong những thuộc tính vô cùng hữu ích của Object C, kể cả ngay khi bạn không có mã nguồn của lớp nhưng bạn vẫn hoàn toàn có thể thêm phương thức cho lớp như thường thông qua thuộc tính này. Đặc điểm này làm giảm đi đáng kể sự kế thừa phức tạp trong C++ khi việc kế thừa chỉ để phục vụ cho việc thêm mới một phương thức. Mặt khác việc chia mã nguồn trên nhiều files cũng giúp ích đáng kể trong việc phát triển.

#import “Fraction.h”

@interface Fraction (Math)

-(Fraction*) add: (Fraction*) f;

-(Fraction*) mul: (Fraction*) f;

-(Fraction*) div: (Fraction*) f;

-(Fraction*) sub: (Fraction*) f;

@end

File thực thi.

#import “FractionMath.h”

@implementation Fraction (Math)

-(Fraction*) add: (Fraction*) f {

return [[Fraction alloc] initWithNumerator: numerator * [f denominator] +

denominator * [f numerator]

denominator: denominator * [f denominator]];

}

-(Fraction*) mul: (Fraction*) f {

return [[Fraction alloc] initWithNumerator: numerator * [f numerator]

denominator: denominator * [f denominator]];

}

-(Fraction*) div: (Fraction*) f {

return [[Fraction alloc] initWithNumerator: numerator * [f denominator]

denominator: denominator * [f numerator]];

}

-(Fraction*) sub: (Fraction*) f {

return [[Fraction alloc] initWithNumerator: numerator * [f denominator] –

denominator * [f numerator]

denominator: denominator * [f denominator]];

}

@end

* Đặc điểm:

– Tên của category phải là duy nhất

– Có thể thêm bao nhiêu lần mở rộng lơp từ category là không giới hạn nhưng với tên là duy nhất.

– Thông thể bổ xung biến thành phần bằng category.

– Có thể sử dụng category để tạo ra các phương thức private. Nếu cần.

MyClass.h

#import

@interface MyClass: NSObject

-(void) publicMethod;

@end

MyClass.m

#import “MyClass.h”

#import

@implementation MyClass

-(void) publicMethod {

printf( “public method\n” );

}

@end

@interface MyClass (Private)

-(void) privateMethod;

@end

@implementation MyClass (Private)

-(void) privateMethod {

printf( “private method\n” );

}

@end

File chính:

#import “MyClass.h”

int main( int argc, const char *argv[] ) {

MyClass *obj = [[MyClass alloc] init];

// this compiles

[obj publicMethod];

// this throws errors when compiling

//[obj privateMethod];

// free memory

[obj release];

return 0;

}

4. Protocols: Giao diện.

Đây hoàn toàn tương đồng với khái miện lớp ảo trong C++ hoặc gọi là giao diện trong C# và Java. Bản thân @protocals không có sự thực thi. Nếu lớp nào cam kết thực thi nó thì trong phần thực thi sẽ implement các phương thức mà protocols khai báo.

 

@protocol Printing

-(void) print;

@end

 

Fraction.h

#import

#import “Printing.h”

@interface Fraction: NSObject {

int numerator;

int denominator;

}

 

-(Fraction*) initWithNumerator: (int) n denominator: (int) d;

-(void) setNumerator: (int) d;

-(void) setDeno minator: (int) d;

-(void) setNumerator: (int) n andDenominator: (int) d;

-(int) numerator;

-(int) denominator;

@end

 

Fraction.m

#import “Fraction.h”

#import

@implementation Fraction

-(Fraction*) initWithNumerator: (int) n denominator: (int) d {

self = [super init];

if ( self ) {

[self setNumerator: n andDenominator: d];

}

return self;

}

-(void) print {

printf( “%i/%i”, numerator, denominator );

}

-(void) setNumerator: (int) n {

numerator = n;

}

-(void) setDenominator: (int) d {

denominator = d;

}

-(void) setNumerator: (int) n andDenominator: (int) d {

numerator = n;

denominator = d;

}

-(int) denominator {

return denominator;

}

-(int) numerator {

return numerator;

}

-(Fraction*) copyWithZone: (NSZone*) zone {

return [[Fraction allocWithZone: zone] initWithNumerator: numerator

denominator: denominator];

}

@end

Complex.h

#import

#import “Printing.h”

@interface Complex: NSObject {

double real;

double imaginary;

}

-(Complex*) initWithReal: (double) r andImaginary: (double) i;

-(void) setReal: (double) r;

-(void) setImaginary: (double) i;

-(void) setReal: (double) r andImaginary: (double) i;

-(double) real;

-(double) imaginary;

@end

Complex.m

#import “Complex.h”

#import

@implementation Complex

-(Complex*) initWithReal: (double) r andImaginary: (double) i {

self = [super init];

if ( self ) {

[self setReal: r andImaginary: i];

}

return self;

}

-(void) setReal: (double) r {

real = r;

}

-(void) setImaginary: (double) i {

imaginary = i;

}

-(void) setReal: (double) r andImaginary: (double) i {

real = r;

imaginary = i;

}

-(double) real {

return real;

}

-(double) imaginary {

return imaginary;

}

-(void) print {

printf( “%_f + %_fi”, real, imaginary );

}

@end

main.m

#import

#import “Fraction.h”

#import “Complex.h”

int main( int argc, const char *argv[] ) {

// create a new instance

Fraction *frac = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

Complex *comp = [[Complex alloc] initWithReal: 5 andImaginary: 15];

id printable;

id copyPrintable;

// print it

printable = frac;

printf( “The fraction is: ” );

[printable print];

printf( “\n” );

// print complex

printable = comp;

printf( “The complex number is: ” );

[printable print];

printf( “\n” );

// this compiles because Fraction comforms to both Printing and NSCopyable

copyPrintable = frac;

// this doesn’t compile because Complex only conforms to Printing

//copyPrintable = comp;

// test conformance

// true

if ( [frac conformsToProtocol: @protocol( NSCopying )] == YES ) {

printf( “Fraction conforms to NSCopying\n” );

}

// false

if ( [comp conformsToProtocol: @protocol( NSCopying )] == YES ) {

printf( “Complex conforms to NSCopying\n” );

}

// free memory

[frac release];

[comp release];

return 0;

}

5. Properties

Thuộc tính gần như bất cứ một ngôn ngữ mới hiện đại nào cũng hỗ chợ khái niệm này, đây là một khái niệm bảo toàn tính đóng gói của tư tưởng OOP.

Đối vơi ngôn ngữ ObC có mốt số những hỗ chợ đặc biệt hơn một chút bạn khai báo sử dụng bằng @properties cũng giống như những ngôn ngữ khác khi bạn sử dụng thuộc tính với ObC bạn sẽ có 2 lựa chọn là @synthesize và @dynamic, với lựa chọn là @synthesize thì mặc nhiên trình biên dịch sẽ giúp bạn sinh ra các phương thức set và get trên thuộc tính. nhưng nếu bạn lựa chọn là @dynamic thì mọi việc bạn phải tự làm lấy.

Hãy xem code

#import

@interface Photo : NSObject {

NSString* caption;

NSString* photographer;

}

– (NSString*) caption;

– (NSString*) photographer;

– (void) setCaption: (NSString*)input;

– (void) setPhotographer: (NSString*)input;

@end

#import

@interface Photo : NSObject {

NSString* caption;

NSString* photographer;

}

@property (retain) NSString* caption;

@property (retain) NSString* photographer;

@end

* Kiểu id

id trong ObC gần tương tự như void* trong C. bạn không cần phải biết rõ kiểu của object khi bạn gọi phương thức trong ObC điều này hoàn toàn khác với C++ bơi đơn giản khi gọi phương thức cũng giống như bạn truyền thông điệp trong ObC. Nếu đối tượng nó có phương thức thì sẽ đáp lại thông điệp mà bạn truyền (gọi phương thức) và phương thức đc gọi. Cũng nguy hiểm đây chứ ..

Ép kiểu động.

Những phương thức dưới đây dùng để kiểm tra kiểu.

– (BOOL) isKindOfClass: classObj >> đối tượng là hậu duệ hoặc thể hiện của classObj

– (BOOL) isMemberOfClass: classObj >> là một thành phần của objClass

– (BOOL) respondsToSelector: selector >> đối tượng có phương thức bởi selector

+ (BOOL) instancesRespondToSelector: selector >> đối tượng đc tạo bởi lớp có đáp ứng selector

– (id) performSelector: selector >> triệu gọi chính sách selector trên đối tượng.

Constructors – hàm khỏi tạo:

Vấn đề là với một lớp thì hàm khởi tạo dùng để sinh đối tượng và cũng là chỗ để tư duy về hàm hủy và cách thức lưu trong bộ nhớ của đối tượng. Về vấn đề hủy đối tượng ta sẽ có một phần riêng và nó hoàn toàn khác biệt với việc viết hàm hủy trong C++ và các ngôn ngữ khác. Tất nhiên không có gì là không thể viết khi bạn đã hiểu rõ và thông thạo ngôn ngữ. Và hẳn nhiên bạn có thể quên hết những luật về khởi tạo đối tượng hàm tạo và hàm hủy của C++ vơi ObC bạn hoàn toàn có thể tự mình chế biến những hàm đó theo ý thích và cũng không có quy luật gì về tên tuổi của hàm, tuy nhiên theo thoi quen truyền thông để giúp style – code chở nên sáng sủa nên dùng bằng các từ như init hoặc tương tự… để định nghĩa hàm khởi tạo

Fraction.h

-(Fraction*) initWithNumerator: (int) n denominator: (int) d;

Fraction.m

-(Fraction*) initWithNumerator: (int) n denominator: (int) d {

self = [super init];

if ( self ) {

[self setNumerator: n andDenominator: d];

}

return self;

}

main.m

#import

#import “Fraction.h”

int main( int argc, const char *argv[] ) {

// create a new instance

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

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

Fraction *frac3 = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

// set the values

[frac setNumerator: 1];

[frac setDenominator: 3];

// combined set

[frac2 setNumerator: 1 andDenominator: 5];

// print it

printf( “The fraction is: ” );

[frac print];

printf( “\n” );

printf( “Fraction 2 is: ” );

[frac2 print];

printf( “\n” );

printf( “Fraction 3 is: ” );

[frac3 print];

printf( “\n” );

// free memory

[frac release];

[frac2 release];

[frac3 release];

return 0;

}

– Từ khóa super để tham chiếu tới lớp cha.

– Từ khóa self tác dụng tương đương như this trong C++. (chính bản thân đang thể hiện của lớp – object hiện tại)

– Kết thúc hàm khởi tạo (init) sẽ trả về chính đối tượng dc tạo ra thông qua từ khóa self.

– Mặc định trong ObC hàm khỏi tạo là – (id) init;

– Trong Object C hàm khởi tạo chỉ có ý nghĩa về mặt tư duy, nó không được đối xử đặc biết giống như C++.

6. Đa hình.

Có lẽ với những trình bày ở trên phần nào giúp bạn mường tượng ra được cơ chế đa hình của Object C. Phần này chỉ là viết thêm nhằm củng cố một số những điểm sau đây.

1. Trong Object C không có từ khóa virtual và thực sự là không cần thiết vì nó sẽ không tạo ra những thứ quá phức tạp giống như C++ vì việc phủ quyết hàm trong Object C là phủ quyết trắng chợn không liên quan gì tới sự kế thừa. nếu 2 hàm giống hệt nhau ở 2 lớp quan hệ cha con thì cũng chẳng sao cả. cũng cần nói thêm là Object C là đơn kế thừa.

2. Quá trình tạo mối liên hệ giữa thể hiện của Object C và phương thức sẽ đc gọi là thời điểm run-time. Điểu này hoàn toàn có ý nghĩa nếu bạn gọi một phương thức mà bản thân đối tượng không có cũng không có lỗi gì. Lỗi chỉ xảy ra khi lời gọi đó dc thực hiện. Tuy nhiên ban cũng dc cung cấp những cơ chế để kiểm soát việc này. đây cũng là một đặc tính Run-Time của Object C nếu bạn quan tâm có thể tìm kiếm thông tin từ việc chuyển tiếp thông điệp (forward) tới một đối tượng khác.

 

* Quản lý bộ nhớ.

Object C có 2 lựa chọn cho việc quản lý bộ nhớ. Thông thường bộ nhớ dc quản lý bởi lập trình viên, Object C có trình biên dịch chỉ thị nhứ “release”, “retain”, “autorelease” là những chỉ thị hỗ chợ lập trình viên mạnh mẽ trong việc quản lý bộ nhớ. Tuy nhiên sự ra đời của ARC đã làm cho việc này trở nên thừa thải. Tất cả sẽ do ARC quản lý, các lập trình viên chỉ cần suy nghĩ logic của vấn đề. Tuy nhiên nếu bạn vẫn thích quản lý bộ nhớ bằng tay cho nó thêm phần phức tạp thì cứ đọc tiếp.

Object C sử dụng một tham chiếu đếm để dò tìm ra những thay đổi trên một đối tượng. Biến đếm này sẽ tăng lên một khi đối tượng dc cấp phát bộ nhớ bằng phương thức alloc, biến đếm này sẽ giảm đi một khi đối tượng được giải phóng bằng phương thức dealloc. Như vậy nguyên lý cấp phát và duy trì bộ nhớ của đối tượng trong Object C dc sử dụng thông qua phương thức alloc và dealloc.

Mặt khác tiện ích khác từ kiểu dữ liệu nil đã nói ở trên đó việc giải phóng bộ nhớ. Trong ngữ cảnh một đối tượng của bạn là bao gồm nhiều những đối tượng khác. những đối tượng khác đó có thể đã dc giải phóng hoặc chưa. như thế bạn sẽ thực hiện lời gọi dealloc trên tập đối tượng mà bạn có, nếu con thì nó sẽ thực hiện giải phóng trong trường hợp bằng nil cũng ok không vấn đề gì (no error) vì nil cũng có thể truyền thông điệp.

Hãy xem ví dụ

# AddressCard.h

#import

#import

@interface AddressCard: NSObject {

NSString *first;

NSString *last;

NSString *email;

}

-(AddressCard*) initWithFirst: (NSString*) f

last: (NSString*) l

email: (NSString*) e;

-(NSString*) first;

-(NSString*) last;

-(NSString*) email;

-(void) setFirst: (NSString*) f;

-(void) setLast: (NSString*) l;

-(void) setEmail: (NSString*) e;

-(void) setFirst: (NSString*) f

last: (NSString*) l

email: (NSString*) e;

-(void) setFirst: (NSString*) f last: (NSString*) l;

-(void) print;

@end

# AddressCard.m

#import “AddressCard.h”

#import

@implementation AddressCard

-(AddressCard*) initWithFirst: (NSString*) f

last: (NSString*) l

email: (NSString*) e {

self = [super init];

if ( self ) {

[self setFirst: f last: l email: e];

}

return self;

}

-(NSString*) first {

return first;

}

-(NSString*) last {

return last;

}

-(NSString*) email {

return email;

}

-(void) setFirst: (NSString*) f {

[f retain];

[first release];

first = f;

}

-(void) setLast: (NSString*) l {

[l retain];

[last release];

last = l;

}

-(void) setEmail: (NSString*) e {

[e retain];

[email release];

email = e;

}

-(void) setFirst: (NSString*) f

last: (NSString*) l

email: (NSString*) e {

[self setFirst: f];

[self setLast: l];

[self setEmail: e];

}

-(void) setFirst: (NSString*) f last: (NSString*) l {

[self setFirst: f];

[self setLast: l];

}

-(void) print {

printf( “%s %s <%s>”, [first cString],

[last cString],

[email cString] );

}

-(void) dealloc {

[first release];

[last release];

[email release];

[super dealloc];

}

@end

# main.m

 

#import “AddressCard.h”

#import

#import

int main( int argc, const char *argv[] ) {

NSString *first =[[NSString alloc] initWithCString: “Tom”];

NSString *last = [[NSString alloc] initWithCString: “Jones”];

NSString *email = [[NSString alloc] initWithCString: “tom@jones.com”];

AddressCard *tom = [[AddressCard alloc] initWithFirst: first

last: last

email: email];

// we’re done with the strings, so we must dealloc them

[first release];

[last release];

[email release];

// print to show the retain count

printf( “Retain count: %i\n”, [[tom first] retainCount] );

[tom print];

printf( “\n” );

// free memory

[tom release];

return 0;

}

# output

Retain count: 1

 

* Giải thích:

Mặt khác Object C cũng cung cấp một cớ chế thông minh thường thường trong việc bạn gọi và sử dụng đối tượng mà không phải quan tâm lo lắng đến việc cấp phát và giải phóng bộ nhớ đó là cơ chế NSAutoreleasePool. Để dùng dc cơ chế này bạn chỉ việc nhớ 2 điều kẹp đoạn code mà bạn muốn kiểm soát vào trong giữa NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init] và [pool release]. Nguyên lý của đồng chí này cũng giống như lời gọi hàm vì thế bạn hoàn toàn có thể sử dụng lồng nhau và sự đóng mở hợp lý (giống như thẻ đóng và mở của XML đó) tự nhiên Object C sẽ đẩy các lời gọi pool sau xuống stack và đặt pool mới trên cùng sau đó nhét các object dc tạo ra trong lòng nó vào cái pool vừa mới tạo nếu song thì giải phóng rồi lại đẩy tiếp thằng pool ở dưới lên cứ thế…

Những thứ này sẽ biến mất nếu sử dụng ARC, bạn vẫn có thể dùng nhưng sẽ qua vài bước để vô hiệu hóa ARC trong chương trình.

7. 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);

 

7.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ị @selector cho 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 SEL là setWidthHeight.

Ở 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 selector. 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.

 

[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 getTheReceiver và 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.

 

7.3. Xử lý ngoại lệ

@try {

}

@catch (CustomException *ce) {

}

@catch (NSException *ne) {

// Bắt lỗi xảy ra tại đây

}

@catch (id ue) {

}

@finally { // 3

// Thi hành lệnh cho dù ngoại lệ có xảy ra hay không?

// Thông thường là đóng các chương trình và các kết nối tới cơ sở dữ liệu

}

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

Bắt các kiểu ngoại lệ chung

– Cách bắt ngoại lệ của C Object hoàn toàn giống với những gì mà các ngôn ngữ khác (C#, Java) làm nên đối với các lập trình viên có kinh nghiêm thì hoàn toàn dễ dàng sử dụng.

– Đây là thứ nên có trong các chương trình để giảm việc phát sinh ra lỗi và dễ dàng sửa chữa các bug trong chương trình

Tagged: , , , , , , , , , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: