//------------------------------------------------------------------------------------------------------
Học ObjC trong 30 phút
§
Thời gian gần đây tôi nghĩ về việc viết một vài
thứ đơn giản về Objective C – bạn biết không, ngôn ngữ kì lạ Apple được sử dụng
cho việc lập trình Mac…Tôi không định chuyển đổi từ Ruby sang ObjC – tôi khá
thích thú với thử thách này (“cái gì, tôi không thể học điều này? Tất nhiên là
bạn có thể!”), bên cạnh đó, không có ngôn ngữ nào là hoàn hảo, và có một vài
ngôn ngữ cấp thấp mà bạn thật sự không nên viết trong Ruby, giống những plugin
cho Finder, Quicklook,…Hơn nữa tôi cũng nhớ là đã đọc một vài chỗ mà nó thực sự
tốt cho một lập trình viên để học một ngôn ngữ mới mỗi năm – do đó, cách đây 2
năm cho Python, một năm trước cho Ruby, và năm nay cho Objective C?:)
§
Tôi đã tìm trên google một vài bài hướng dẫn
nhanh, đọc một số bài, và tôi thấy rằng ngôn ngữ này thực sự rất đơn giản, nó
chỉ thấy phức tạp rắc rối do cú pháp và những ký hiệu; nhưng một khi bạn bắt
đầu dịch mọi thứ trong đầu bạn, tất cả sẽ trở nên thật quen thuộc. Tất nhiên,
đó là việc hoàn toàn khác để hiểu cái gì đang diễn ra với code của họ và để có
thể viết code của chính bạn; nhưng trong trường hợp này, thật dễ dàng để đi từ
“Oh my god, WTF cái quái gì đây?” đến trạng thái mà khi đó bạn có thể xem code
ObjC và hiểu nó như thể là nó được viết trong Java hay một ngôn ngữ quen thuộc
nào đó.
§
Tôi có một vài chú ý khi tôi đọc các bài hướng
dẫn, và tôi đang viết ở đây để mọi người có thể học chúng nhanh hơn – đó chỉ là
một “diff”, do đó tôi không mô tả chi tiết rõ ràng cho mọi người đã biết C,
Java, Ruby,…Bạn có thể xem như là một bài hướng dẫn của một người đàn ông tội
nghiệp…^^Mặc dù tôi cảnh báo bạn rằng tôi đã dành tổng cộng một ngày để xem
code ObjC, cho nên một phần nào đó tôi đã viết ở đây có không hoàn toàn đúng.
Tất cả những điều này được dựa trên những kiến thức tôi đã đọc, không phải là
kinh nghiệm của tôi. Sản phẩm này được cung cấp mà không có bảo hành nhé…^^
The language
Ngôn ngữ
§
ObjC là một tập cha của C. Điều này có
nghĩa là tất cả những thuộc tính được viết trong chương trình C về mặt lý
thuyết được biên dịch như chương trình ObjC mà không có bất cứ sự thay đổi nào.
Mọi thứ làm việc trong C, cũng làm việc trong ObjC. ObjC thêm một vài tính năng
mới so với C, bao gồm OOP và Smalltalk-like message passing(truyền thông
điệp Smalltalk-like).
§
ObjC là một ngôn ngữ mà nó được biên dịch thành
mã máy, cũng giống như C/C++, và điều đó có lẽ làm cho nó nhanh hơn Java,
Python hay Ruby, những ngôn ngữ chạy trong máy ảo.
§
Mặt khác, ObjC có nhiều tính năng mà làm nó linh
hoạt hơn nhiều C++, và giống hơn với Ruby hay Python. ObjC hỗ trợ cả hai static
typing và dynamic typing, dựa trên cách các biến được khai báo. Thật không may,
tất cả những cái đó làm nó chậm hơn so với C++. Tôi không biết chậm hơn bao
lâu, và tôi cũng không thể tìm ra một chuẩn riêng nào đó…Tôi đoán tôi cần phải tự
mình viết.
§
Phiên bản mới nhất của ngôn ngữ này là 2.0 (cái
này không biết bây giờ phiên bản mấy rồi :D),
nó được phát hành gần đây với Leopard; nó thêm một vài tính năng mới,
giống như cơ chế thu dọn rác, những thuộc tính, hay vòng lặp for-each.
Source code
Mã nguồn
§
Những file được tổ chức theo cách giống như
C/C++: có những file header (*.h), nó chứa những khai báo interface cho những
lớp, và phần mã nguồn (*.m), mà nó cung cấp sự thực thi. Cảm ơn đến Stack Overflow, đuôi mở rộng .m có nghĩa là
“messages” hay là “methods”.
§
Trong ObjC không có namespaces giống như những
ngôn ngữ khác, thay vào đó, để có thể phân biệt những lớp từ những frameworks
khác nhau, name prefixes được sử dụng. Ví dụ, nhiều lớp core ObjC có tiền tố
“NS” (NSString, NSObject,…), viết tắt cho “NextStep” (nó là một môi trường Unix
được tạo trong thập niên 90, mà nó được sử dụng như là một cơ sở cho MacOSX khi
nó được phát triển.)
§
Thực thi chương trình bắt đầu trong hàm int
main().
§
Những header có thể được include bằng cách sử
dụng #include,
nhưng sẽ tốt hơn khi dùng #import, cái này nó làm việc giống
như include, ngoại trừ nó không bao giờ include cùng một header 2 lần (do đó
bạn không phải làm những việc ngu ngốc như #ifndef/#define giống như bên C++).
§
Những từ khóa được thêm bắt đầu với “@” để phân
biệt chúng với những từ khóa trong C.
§
Chương trình có được biên dịch bằng cách sử dụng
gcc, giống như C/C++, những bạn cần thêm – framework Cocoa
để sử dụng thư viện chuẩn ObjC (hoặc, nó được gọi trong ObjC, “framework”)
Methods
Phương thức
§
Đây là một điều thú vị nhất trong ObjC. Bạn
không thể gọi những phương thức bằng cách:
foo.bar
,
hay foo->bar,
hay foo-whatever-bar.
Bạn gọi chúng với [foo bar]…và obj.foo.bar thành [[obj
foo] bar]. Một chút bất tiện
IMHO, bởi vì khi bạn viết theo một trình tự “object method method method…” sau
đó khi kết thúc bạn phải quay lại chỗ bắt đầu và thêm một số lượng những ngoặc
đơn để nối với những dấu đóng ngoặc đơn…
But once you install a
proper regular expression in your head that changes bracket notation to dots, ít
nhất là dễ đọc hơn.
§
Một điều bất thường về phương thức là những tham
số trong đa số những trường hợp được cho bởi labels, chúng được dùng
trong việc gọi phương thức. Do đó việc gọi những phương thức với nhiều hơn một
tham số sẽ giống như thế này:
[appleStore buyMacs: 2 withRAM: 4
withCPU: 2.66] |
§
Đây là một trong những ý tưởng được đưa ra từ
Smalltalk. Nó làm code dài dòng hơn, nhưng ở khía cạnh khác, nó trở nên dễ đọc
hơn nhiều. Bên cạnh đó, nó khá giống với những tham số của Python foo=bar
và Ruby : foo=>bar, vì vậy
thực sự không có gì mới.
§
Những label thực sự là từ tên đầy đủ của phương
thức. Do đó phương thức ở trên đưa chuyển thành như: buyMacs:withRAM:withCPU:.
§
Những phương thức không thể được overload theo
kiểu của tham số, do đó không thể có 2 phương thức foo(int) và foo(char*).
Nhưng chúng có thể được overload bằng labels, do đó bạn có thể có những phương
thức như: buyMacs:, buyMacs:withRAM:, buyMacs:withMonitors:
và …
§
Phương thức trên thường được dùng để thay thế
cho default parameter values trong
những hàm, mà chúng không tồn tại trong ObjC. Do đó nếu bạn muốn tham số thứ
hai để có một giá trị mặc định, bạn phải viết 2 phương thức, một với một tham
số, và cái khác với 2…
§
Giống như trong Python hay Ruby, việc gọi một
phương thức không tồn tại thì không ném ra một lỗi biên dịch, nhưng nó ném ra
một ngoại lệ runtime, cái đó có thể được bắt và xử lí.
§
Còn gì nửa?, việc gọi những phương thức không
tồn tại có thể bị bắt lấy và được xử lý trước khi một ngoại lệ bị ném ra. Điều
đó có nhắc bạn về việc gì không? method_missing của Ruby, tất nhiên. Ở đây, phương thức có thể được sử dụng cho
điều này là: forwardInvocation:.
§
Những tác giả bài tut thông thường cứ khăn khăn
là trong ObjC bạn không gọi những phương thức, bạn “gửi thông điệp”. Tôi nghĩ
đây chỉ là một vấn đề về tên gọi, tôi không hiểu việc gọi phương thức với
cái “gửi thông điệp” khác nhau cái gì.
Nhưng tôi cũng có thể sai.(Những phương thức cũng thể được gọi là những “selectors”).
Data types
§
ObjC có cả hay dạng primitive và object,
giống như C++ hay Java. Không giống như C++, nó không có kiểu giá trị cho những
đối tưởng, mà chỉ có cho những con trỏ, do đó không có Foo x, mà chỉ là: Foo
*x.
§
Kiểu dữ liệu thông thường của C (int, float, …)
có thể được sử dụng, mặc dù đó có thể không thường xuyên được khuyến khích. Ví
dụ, có những kiểu như NSInteger, NSUInteger, hay CGFloat,
đó là những phiên bản kiến trúc an toàn cho int, unsigned int, float và …Cũng
có một class được đặt tên là NSNumber được dùng cho
boxing/unboxing những kiểu primitive trong những trường hợp khi chúng ta cần
truyền một đối tượng đến nơi nào đó.
§
Ngoài kiểu chuỗi strings của C (char
*), cũng có kiểu chuỗi của ObjC strings (NSString). Để tạo chuỗi
kí tự, sử dụng kí hiệu: @”some text”. NSString có thể được
chuyển thành char * bằng việc sử dụng cString () (cái này bị phản đổi..^^)
hay những phương thức UTF8String của NSString (ví dụ, khi
bạn cần sử dụng chúng như những tham số cho hàm printf()).
§
Boolean được gọi là BOOL, và giá trị của nó là…YES
và NO.
§
Có một kiểu chung được gọi là id,
nghĩa gốc của nó là “any object”. Một cái gì đó giống Object *, nhưng có một sự
khác nhau chút chút. Hay từ này là cánh cửa của kiểu đánh máy dynamic. Nếu bạn
khai báo một biến là Foo *x, nó sẽ làm việc giống như
C++, thử gọi một cái gì đó mà không hiệu lực trong lớp Foo, và trình biên dịch
sẽ cảnh báo rằng (mặc dù trong ObjC nó không đóng với một lỗi, nó chỉ là in một
cảnh báo - bởi vì đôi khi mã có thể
đúng, cho dù nó không rõ ràng đối với trình biên dịch ). Nhưng nếu bạn khai báo
một biến như: id x, nó sẽ làm việc giống như trong Ruy – trình biên dịch cho
phép bạn gọi bất cứ cái gì bạn muốn trên nó, và chỉ ở tại runtime nó sẽ được
quyết định nếu đối tượng có thể xử lí method hay không.
§
Null được gọi là nil. Và apparently you
can call methods on it and the universe won’t implode. Hơn thế nữa, bạn có thể
gọi bất kì phương thức nào trên nó, và nó sẽ luôn return nil - điều này có nghĩa là thông thường bạn không
phải kiểm tra nếu đối tượng là nil. Bạn chỉ có thể gọi cái gì cũng được nếu bạn
muốn trên nó, và nếu nó là nil, nó chỉ “ngồi” ở đó và bỏ qua bạn. Nó có thể làm
cho việc code đơn giản hơn một xíu, nhưng mặt khác nó có thể làm cho việc
debugging khó khăn hơn - bạn không phải
ngay lập tức lấy một ngoại lệ nếu cái gì đó không nên là nil…
§
Những con trỏ đến lớp (For pointers to classes),
nil được viết hoa (Nil). Đừng hỏi tôi tại sao…
§
Giống như NSNumber cho ints, có một bộ cho giá
trị nil – lớp NSNull. You can’t put a nil into an NSArray, but you can put a
NSNull there (usage: [NSNull null]).
§
SEL
(viết tắt cho “selector”) là một dạng của những con trỏ phương thức. Để lấy một
con trỏ SEL. Sử dụng từ khóa @selector với chữ kí phương thức,
vd: @selector(methodName:withArg:).
§
Tất cả những đối tượng có một phương thức được
đặt tên là description, một cái tên giống như toString trong Java.
§
Nhiều dạng đối tượng built-in có những phiên bản
mutable
và non-mutable:
có NSString
và NSMutableString,
NSArray
và NSMutableArray,
và nhiều cặp khác,…
Classes
§
Lớp interfaces (*.h) được khai báo được sử dụng
với từ khóa @interface:
@interface MyClass:
NSObject { // <--
NSObject is the superclass // now, a list of instance
variables: int foo; ... } // and now - a list of methods: - (void) print; - (void) setValue: (int) v; - (void) setValue: (int) v andAnother: (int)
a; - (int) value; - foo; + (int) numberOfInstances; + (void) initialize; // class
initializer @end |
§
Cú pháp định nghĩa phương thức khá khác với
C/C++, nhưng nó khá dễ hiểu. Những phương thức với một kí hiệu – là những thể
hiện của phương thức, và những cái đó với một dấu + là phương thức static.
§
ObjC sử dụng kế thừa đơn, giống như Java hay
Ruby.
§
Nếu bạn không đề cập đến kiểu được return một
cách rõ ràng (giống như phương thức foo ở trên), kiểu mặc định là id.
§
Nếu một lớp có một phương thức lớp đặt tên là initialize,
nó được gọi một khi một lớp được sử dụng cho lần đầu tiên (giống như hàm tạo static
trong C#).
§
Từ khóa khác được sử dụng trong khai báo
interface, @class, được sử dụng cho khai báo trước, giống như C++. Nếu bạn
cần đề cập một lớp trong interface của lớp khác, để giảm liên kết giữa những
lớp mà bạn có thể khai báo nó với @class Klass thay vì #import
<klass.h>.
§
Lớp implementation (*.m) được kèm theo từ khóa @implementation
… @end
@implementation MyClass - (void) setValue: (int) v { ... } @end |
§
Những khai báo biến không có kí hiệu +/- phía
trước chúng, do đó nếu bạn muốn có một biến static trong một lớp, khai
báo nó bằng cách sử dụng từ khóa C static trong file header, bên ngoài khối
@interface (e.g. static int instances;).
§
Những biến được định nghĩa trong lớp được truy
cập bằng cách sử dụng toán tử ->, ví dụ: person->name.
§
Biến truy cập được thiết lập bằng cách sử dụng
từ khóa @public, @private, và @protected, chúng được sử
dụng giống như trong C++ hay Ruby, không giống như trong Java – bạn thêm từ
khóa trước một nhóm biến, không trước mỗi biến. Truy cập mặc định là
@protected. Những phương thức thì luôn là public; bạn có thể mô phỏng những
phương thức private không phải bằng cách thêm kí hiệu của chúng đến @interface,
mà chỉ cần viết trong @implementation.
§
ObjC 2.0 giới thiệu “properties”, nó giống như
thuộc tính đối tượng trong ngôn ngữ khác:
o
Bên
trong @interface, trong khối phương thức mà bạn khai báo, ví dụ như: @property
int age;. Việc này giống như bạn khai báo thủ công một getter (int)
age (in ObjC getters không có tiền tố “get”) và một setter (void)
setAge: (int) age. Bạn vẫn phải đề cập một việc nối biến được khai báo
trong lớp trong khối biến.
o
Bên
trong @ implementation, bạn viết là
@synthesize age
;
nó tạo ra getter và setter cho biến. Bạn cũng có thể cung cấp những
implementation tự chế của chính bạn.
o
Để
tăng tính rắc rối ^^, những thuộc tính thì không được truy cập bằng [obj
age] hay là obj->age, mà phải là obj.age…
o
Những
thuộc tính có thể có những tùy chọn cộng thêm được chèn trong ngoặc sau từ khóa
@property, giống như ri:
@property (readonly)
int age;
. Tùy chọn chỉ đọc có nghĩa là nó chỉ có getter được
tạo ra.
§
Trong ObjC, một phần từ việc kế thừa từ những
lớp, bạn cũng có thể…thêm code đến lớp đang tồn tại. Thậm chí trong những lớp
built-in. Nghe có vẻ hơi dở, có chắc vậy không? Nó không mạnh như cơ chế “open
classes” trong Ruby (ví dụ: bạn không thể thêm một biến instance mới), nhưng nó
dường như lại là cách hay. Ở đây nó được gọi là “categoties” (bởi vì nếu bạn có
một lớp dài, bạn có thể chứa những phương thức của nó trong một vài category và
đặt chúng trong những file khác), và ở đây là cách nó thực hiện:
@interface ExistingClass
(SomeNewName) ...methods... @end |
§
Sau khi bạn include cả hai header cũ và header
mới trong file implementation, và voila – bạn có một lớp với những phương thức
mới được thêm.
§
Cũng có cách thứ 2, một cơ chế gọi là “posing”.
Với posing, thay vì thêm những phương thức đến một lớp được chọn, bạn tạo một
lớp con của lớp đó, và sau đó bạn khai báo lớp con đó “pose” như lớp cha, có
nghĩa là lớp cũ sẽ bị thay thế bằng một cái mới. Bạn làm điều này bằng cách sử
dụng phương thức poseAsClass:
[SubClass poseAsClass:
[SuperClass class]]
;
.
§
Hình như posing bị phản đối, do đó nó không thực
dụ không nên được sử dụng bất cứ khi nào; Tôi chỉ vừa thêm nó ở đây để bạn biết
cái này có nghĩa gì khi bạn thấy nó.
Loops, conditions and operators
§
Những cái này giống như bên C – for,
while,
if…
§
Đối với tập hợp trong ObjC, bạn có thể sử dụng
Java – giống như enumerators:
NSEnumerator *enum
= [array objectEnumerator]; while (i = [enum
nextObject]) { ... } |
§
Trong ObjC 2.0, cũng có vòng lặp for-each,
được gọi là “fast enumeration” (bới vì nó hình như thuận tiện hơn cách cũ):
for (Foo *foo
in list) { ... } |
§
Toán tử so sánh object identity ==,
và so sánh giá trị bạn cần gọi một hàm:
[x isEqual: y]
.Objects
Đối tượng
§
Bên trong những phương thức object,việc tham
chiếu đến đối tượng được gọi là self, giống như trong Python hay
Ruby.
§
Để gọi những hàm implementations
của superclass, ta sử dụng tham chiếu super. Ví dụ, [super foo] gọi là phiên
bản của super của phương thức foo.
§
Việc tạo những đối tượng gồm 2 phần: đầu tiên là
ta gọi alloc trên class để phân bổ bộ nhớ, sao đó init
(hay một việc khác nào đó, hoặc khởi tạo giá trị cụ thể nào đó) trên đối tượng
để khởi tạo nó, vì thế nó giống như thế này:
Mac *box = [[Mac alloc]
init]; |
§
Nếu tôi nhớ không nhầm thì, nó giống như trong
Ruby, nhưng nó có những vấn đề phía sau ngữ cảnh - Foo#allocate và Foo#initialize
được gọi khi bạn viết Foo.new.
§
Nếu bạn muốn có một vài hàm tạo biến thể, bạn có
thể viết chúng giống như thế này:
- (ClassName*) initWithParam: (int) one andAnother:
(int) two { // first, call any
initializations defined in superclass self
= [super
init]; if
(self)
{ // self could be nil if something went wrong // ... set some
instance variables and stuff } return
self ;
// won't work without this } |
Và sau đó bạn sử dụng nó giống như thế này:
ClassName* var = [[ClassName
alloc] initWithParam: 5
andAnother: 6];
Protocols
Giao thức
§
Những protocol về cơ bản nó giống như interface
của java - danh sách của những phương thức mà không implement, mà chúng có thể
được implement bởi những lớp. Việc khai báo những protocol giống như khai báo
một lớp:
@protocol
FooInterface - (int)
foo; -
(void) bar; @end |
§
Để đánh dấu một lớp như là việc implement một
interface, thì ta thêm tên interface trong cặp dấu: <>
@interface
MyClass: NSObject <Printable,
FooInterface> |
§
Những phương thức được khai báo trong
implemented protocol thì không cần được liệt kê bên trong khai báo @interface.
§
Giống như trong Java, bạn có thể khai báo những
biến mà nó trỏ đến bất kì cái gì mà implement một interface:
id foo = [[MyClass alloc]
init]; |
§
Bạn có thể gán bất kì đối tượng nào đến biến
foo, miễn là nó implement FooInterface.
§
Cũng có thể được gọi là: "informal
protocols", chúng chỉ là những danh sách của các phương thức được
publish ở một nơi nào đó trong tài liệu mà lớp của bạn phải hoặc có thể định
nghĩa, nhưng thực tế của việc implement protocol thì không được đề cập rõ ràng
trong code. Điều này thường được làm bằng cách thêm một category đến một lớp,
được đặt tên giống như protocol, cái này nó chứa những phương thức được yêu
cầu.
Memory management
Quản lý bộ nhớ
§
Phiên bản cũ: giống như C, ObjC dựa trên nó, bạn
phải nhớ release tất cả bộ nhớ mà bạn cấp phát, và nếu bạn quên điều đó, bạn sẽ
thấy leak (rò rỉ) bộ nhớ (và nếu bạn release quá nhiều, bạn sẽ bị
segfaults).
§
Phiên bản mới (từ 2.0 trở lên): ObjC bao
gồm garbage collector (bộ
thu nhặt rác), do đó bạn chỉ việc bật nó trong settings của Xcode và quên cái
việc quản lý bộ nhớ :) . Nó khá bất thường cho một ngôn ngữ được biên dịch đầy
đủ để có một garbage collector, và nó làm cho ObjC khá là
độc đáo (đặc trưng).
§
Nhưng việc giới thiệu garbage collector
trong phiên bản 2.0 không có nghĩa là mọi người sẽ bắt đầu sử dụng ngay lập tức
(nó chưa được kích hoạt trên iphone), do đó ở đây có một vài chi tiết về quản
lý bộ nhớ:
o
Ngay
cả khi không có garbage collector, việc quản lý bộ nhớ thì nó đơn giản hơn
chút so với C/C++.
o
Sự
khác nhau ở đây là bạn không phải suy nghĩ chính xác là ai nên có trách nhiệm
cho việc phá huỷ một đối tượng. Mỗi lần bạn chứa một tham chiếu đến nó, bạn gọi
[obj
retain], mà nó tăng "retain
count" của nó lên (số lượng những tham chiếu); và khi bạn không cần nó
nửa, bạn gọi [obj release]. Nếu bạn làm retain count về 0 (nó bắt đầu
lúc 1), đối tượng sẽ được release, nếu không - không có gì xảy ra. Do đó
mỗi đối tượng có thể có vài "owners" và they all dispose of it
in the same way.
o
Khi
đối tượng bị huỷ, hàm huỷ của nó - một phương thức được gọi là dealloc
- sẽ được gọi. Trong phương thức này, bạn có thể gọi release trên tất cả
những tham chiếu đến những đối tượng khác mà bạn chứa trong đối tượng đó. Bạn
nên gọi dealloc của super.
o
Khi garbage
collector được bật lên, tất cả những phương thức giống retain, release,... được
bỏ qua, và dealloc được gọi. Thay vào đó, phương thức finalize
gets được gọi khi một đối tượng được garbage collected.
o
Cách
khác để quản lý bộ nhớ là điều gì đó được gọi là "autorelease pools". Chúng là dạng đa quản lý đối tượng, những
trường hợp của lớp NSAutoreleasePool, và bạn có thể gán những đối tượng đến chúng
bằng cách dùng [obj autorelease]. Sau đó, khi một autorelease pool được
release (sử dụng [pool drain]) - thuật ngữ tuyệt vời :), nó tự động release tất
cả những đối tượng gán đến nó.
o
Bạn
phải cẩn thận về những đối tượng mà nó đã autorelease khi bạn get chúng, và
chúng nên được (auto ) release bởi bạn. Ví dụ, những đối tượng được tạo ra mà
không alloc, nhưng đang dùng phương thức thức static trong những lớp
cơ bản giống như NSString, ví dụ [NSString stringWithFormat: ...]
(một cái gì đó nó giống sprintf()), thường là nó đã được
autorelease. Bạn không thể gọi release chúng, bởi vì điều đó sẽ gây ra một
segfault khi pool cố gắng release chúng. Luật chung là: khi bạn tạo một đối
tượng sử dụng phương thức alloc hay copy, bạn cần release
chúng, and if you get it through some other means, usually someone else
will release it.
o
Với
release/retain, bạn cũng phải cẩn thận cách bạn viết thuộc tính setters (nếu
bạn không dùng @synthesize). Bạn phải release cả hai đối tượng cũ và retain
đối tượng mới; nhưng bạn không thể release trước khi bạn retain, bởi vì nếu bạn
trỏ đền cùng một đối tượng, nó sẽ bị deallocated khi release. Do đó bạn phải
gọi retain trước khi release, hay kiểm tra con trỏ nếu chúng không cùng thời
điểm bắt đầu của setter, hay sử dụng autorelease thay vì release.
Reflection
§
ObjC thì nó năng động hơn C hay C++, mặc dù thực
tế là nó là ngôn ngữ được biên dịch mạnh mẽ. Ở đây là một vài ví dụ của những
hàm liên quan đến reflection:
o
isKindOfClass
, isMemberOfClass
–
like kind_of?, instance_of? in Ruby
o
respondsToSelector
, instancesRespondToSelector
–
tells if an object has a specific method (like respond_to? in Ruby)
o
Có
nghĩa là nếu một đồi tượng có một phương thức cụ thể (giống như respond_to?
trong Ruby)
o
performSelector
– calls a specified method on the
object (like send(:method_name)) (gọi một phương thức xác định trên một đối
tượng) (giống như send(:method_name))
o
conformsToProtocol(@protocol(FooInterface))
– tells if a class implements a
protocol - có nghĩa là nếu một lớp implements một protocol.Exceptions and debugging
§
Những ngoại lệ làm việc giống như những ngôn ngữ
hiện đại khác: chúng được đại diện bởi những lớp kế thừa từ NSException, và bạn
sử dụng từ khoá @try, @catch và @finally để chặn ngoại lệ
được ném ra trong một khối và xử lí chúng. Sử dụng @throw e để ném ngoại lệ
e, và @throw để ném lại một ngoại lệ trong khối catch.
§
Hai phương thức mà có lẽ hữu ích trong
debugging:
o
NSAssert(x != 0, @"X must not be
zero")
–
throws exception if x == 0
o
ném
ngoại lệ nếu x==0;
o
NSLog(@"foo bar %@", x)
– outputs the string (+ some info)
on stderr, and also adds the same line to /var/log/system.log (which can be
viewed with “Console” application).
o
Đầu
ra là chuỗi (+ một vài thông tin) trên stderr, và cũng thêm cùng dòng
đến /var/log/system.log (mà có thể được xem với ứng dụng Console).
Và đó là tất
cả…nếu bạn không biết xíu nào về ObjC, và bạn đã có tính nhẫn nại để đọc hết
bài viết này, tôi hi vọng bạn sẽ có một vài kiến thức về ObjC. Dù sao đi nữa,
bây giờ bạn không nên vừa chạy vừa hét khi bạn thấy code ObjC…ít nhất là tôi sẽ
không làm như vậy…;)
No comments:
Post a Comment