Giới thiệu về Objective-Cx: Tham chiếu liên kết và Selector

MỤC LỤC

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. Đư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.

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.

Selector

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

Xử lý ngoại lệ Code

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

    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 init trả 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. Ý nghĩa từ ví dụ này đó là, ta luôn luôn phải trả về nil trong phương thức init nế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 alloc và init.

    Phương thức alloc, new, copy và retain đề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. 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ớ.

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

    Objects, Messaging, Classes

    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 đó.

    Class Objects

    Compiler sẽ tạo một object duy nhất gọi là class object để miêu tả bao method class. Class object này sẽ truy cập tất cả các thông tin có trong class, và có thể sử dụng để tạo ra các instances mới. Class object được thể hiện bằng tên class, như ví dụ sau đây, class object Rectangle trả về phiên bản của class nhờ method version thừa kế từ class NSObject.

    Ta coi ví dụ tiếp theo đây để so sánh instance methods được gửi bới class object và các methods được gửi bởi instance. [foo someMethod]; // Message gửi bởi instance foo [MyClass someMethod]; // Message gửi bởi class object MyClass. Trong ví dụ trên, dòng đầu tiên có nhiệm vụ tạo ra một instance dạng MyClass (coi cách tạo instance ở phần bên dưới).

    2 dòng tiếp theo ta thấy có 2 method được gọi cùng tên là someMethod, tuy nhiên vai trò của nó khác nhau. Ngược lại someMethod trong dòng code thứ 3 là class method được gửi bởi class object MyClass, nó có thể truy cập vào các static variables. Từ đó ta có thể thấy là instance method và class method có thể đặt trùng tên với nhau.

    Về chức năng ta có thể hiểu class methods giống như các static methods trong ngôn ngữ C+. Ta coi cách khai báo class MyClass như sau (chi tiết cách tạo class coi phần định nghĩa một class). Như ta thấy ở trên thì cách khai báo methods có khác nhau ở ký hiệu “+” hay “-” để thể hiện là instance method hay class method.

    Khởi tạo một Class Object

    Tất cả các objects, classes và instances cần một interface để hoạt động hiệu quả trong hệ thống được dựng bằng Objective-C. Khi hệ thống đang chạy và object nhận được một message mà nó không thể trả lời với method thích hợp (vì class không thực thi method đó) lúc này hệ thống sẽ quyết định thực thi method trong class cha của nó (NSObject class). Cần chú ý rằng tất cả các classes của chúng ta nên kế thừa NSObject class.

    Class Interface

    Kiểu trả về của method được để trong dấu ngoặc đơn () như trong ví dụ sau, method trả về kiểu float. Các parameters được khai báo nằm phía sau dấu “:”, trong ví dụ sau là method setRadius với một parameter aRadius. Nếu một method trả về không chính xác kiểu được khai báo, nó sẽ trả về kiểu id mặc định.

    Khi có nhiều hơn một parameter, ta có cách khai báo tương tự như message, các parameter được khai báo sau dấu “:” và phía trước là tên method. Chú ý là theo thói quen trong interface ta thường để các instance variables, đây là một phần dữ liệu của mỗi instances. Chúng ta có thể khai báo như ví dụ trên, tuy nhiên không làm như thế vì phần interface sẽ được public cho mọi người xem, cho nên chúng ta chỉ nên đưa các properties và methods còn các instance variables riêng nên khai báo trong phần implement.

    Phạm vi instance variable

    @package Instance variable chỉ có thể truy cập trong cùng một frame work, library hoặc.