2009-08-26 8 views
5

Cú pháp nhỏ này có đôi chút nhầm lẫn với tôi trong Mục tiêu-C.Mục tiêu-C: Khi nào nên gọi self.myObject vs chỉ cần gọi myObject

Khi nào tôi nên gọi self.myObject vs chỉ cần gọi myObject?

Có vẻ như dự phòng tuy nhiên chúng không thể hoán đổi cho nhau.

Có ai đó vui lòng khai sáng cho tôi không?

+0

Tôi tìm thấy một bài đăng tương tự tại đây: http://stackoverflow.com/questions/1051543/should-i-use-self-keyword-properties-in-the-implementation – Jonah

Trả lời

8

Nếu bạn chỉ truy cập vào chúng, không có nhiều lý do để sử dụng self.member. Nếu bạn đang thực hiện nhiệm vụ, sẽ tốt nếu bạn làm nhiều hơn tham số @property (assign) đơn giản - ví dụ: giữ lại, sao chép, v.v. để có thể lưu trên mã bạn đang viết. Ví dụ:

myObject = anotherObject; 
self.myObject = anotherObject; 

Lựa chọn thứ hai sẽ đảm bảo rằng bạn đang thực sự gán đối tượng theo cách bạn muốn (sao chép, tăng số lần lưu giữ, v.v.). Nó không khác với [self setMyObject:anotherObject].

Vì dấu chấm được thay thế cho thông báo bởi trình biên dịch (tương tự như cách x[5] trở thành *(x + 5*sizeof(x)) trong công việc mảng thông thường), không có phí hoặc hiệu quả bổ sung khi sử dụng ký hiệu chấm trên các thông báo thường.

1

Bạn hầu như không bao giờ nên gọi người truy cập thuộc tính từ bên trong việc triển khai cùng một lớp. Các phương thức thể hiện của lớp có quyền truy cập thuận tiện vào trạng thái bên trong, vì vậy thường có nghĩa là truy cập trực tiếp vào trạng thái đó.

Nếu bạn đang sử dụng accesors tổng hợp, sau đó gọi cho họ chỉ cần thêm (có thể) chi phí không cần thiết. Nếu người truy cập có triển khai phức tạp hơn, thì bạn chỉ làm mờ mục đích của mã.

Cuối cùng, một số người mới dùng Objective-C sử dụng cú pháp self.property và người truy cập tổng hợp để cố gắng tránh phải hiểu về quản lý bộ nhớ Cocoa. Bạn thực sự cần phải tìm hiểu cách nó hoạt động, vì vậy cố gắng tránh làm như vậy là phản tác dụng.

+0

Chỉ vì bạn có thể fiddle với trạng thái nội bộ của đối tượng tất cả mọi thứ không có nghĩa là bạn nên làm thế. Và chỉ vì bạn hiểu cách hoạt động của quản lý bộ nhớ không có nghĩa là bạn sẽ làm điều đó một cách hoàn hảo cho tất cả các nhóm. Sao chép trách nhiệm quản lý bộ nhớ của bạn trong một loạt các phương pháp là yêu cầu lỗi. – Chuck

+0

Tôi kính trọng không đồng ý. Nếu các lớp của bạn có rất nhiều trình tiếp cận @ synthesize'd, thì chúng có thể được thiết kế kém. Nếu bạn đã triển khai các trình truy cập không tầm thường, thì bạn cần phải cẩn thận khi sử dụng chúng một cách thích hợp. Người truy cập thuộc tính được dự định sẽ được sử dụng để tạo giao diện * bên ngoài * cho lớp học của bạn. đôi khi, nó sẽ có ý nghĩa cho lớp học của bạn để sử dụng nó bên ngoài giao diện nội bộ, nhưng thường, đó là không cần thiết (hoặc phản tác dụng). –

+0

Trong mọi trường hợp, nếu bạn thực sự muốn sử dụng accessors, sau đó sử dụng "self". cú pháp chỉ che khuất những gì đang diễn ra, vì vậy bạn nên sử dụng nhắn tin rõ ràng. Nếu bạn đang đặt thuộc tính, "[self setFoo: value]" chỉ dài hơn 5 ký tự "self.foo = value". Đối với truy cập đọc, sự khác biệt thậm chí còn ít hơn. Bạn sẽ chỉ viết mã một lần, vì vậy bạn nên cố gắng làm cho nó rõ ràng hơn những gì đang xảy ra khi bạn (hoặc người khác) đọc nó sau này. –

1

Nếu bạn đang sử dụng Dữ liệu cốt lõi, về cơ bản bạn luôn sử dụng các trình truy cập vì một số thuộc tính có thể không được tải từ kho lưu trữ liên tục cho đến khi cần thiết. (Giả sử bạn đang sử dụng một cửa hàng SQLite, anyway.)

Nếu bạn không sử dụng Dữ liệu cốt lõi, bạn thường an toàn chỉ sử dụng myObject trực tiếp nếu bạn đang chỉ đọc giá trị. Nếu bạn đang sửa đổi giá trị của myObject, bạn cần phải sử dụng accessors để đảm bảo rằng bất kỳ đối tượng khác quan sát giá trị của tài sản đó được thông báo đúng. Nói cách khác:

// Not changing the value of myObject, so no accessor needed 
[someMutableArray addObject:myObject]; 

// Changes the value, so you need to use the accessor 
self.myObject = newObject;  
[self setMyObject:newObject]; // Exactly identical to the previous line. 

Nói chung, mặc dù có rất ít chi phí; Tôi thích luôn sử dụng accessors, ngay cả trong cùng một đối tượng. (Tất nhiên, có tranh luận về việc sử dụng chúng trong initializers, nhưng đó là một vấn đề riêng biệt.)

3

Hrm, tôi không thể nói rằng tôi đồng ý với Mark hoặc Cinder6.

Vâng, tôi đồng ý ở phần đầu tiên. :-) self.foo đang gọi phương thức -foo. Plain foo đang truy cập vào mã vạch foo.

Trong hầu hết các trường hợp, bạn phải luôn thực hiện các phương pháp của mình.Chúng ở đó để tóm tắt bạn khỏi kho lưu trữ thực tế và tránh xa bất kỳ hành vi nào khác có thể cần thiết. Hãy suy nghĩ về những gì sẽ xảy ra nếu bạn sau đó phân lớp của bạn. Đối với hầu hết các phần bạn muốn được gọi phương pháp công cộng của riêng bạn ở những nơi mà bạn truy cập vào các chức năng mà họ bao gồm.

Ngoại lệ nằm trong đối tượng init và teardown, và bên trong các trình truy cập thuộc tính khi bạn không tổng hợp chúng. Trong đối tượng init và teardown, bạn thực hiện không muốn gọi triển khai lớp con của các phương thức, vì các phương thức đó không cần phải xử lý đối tượng của bạn trong trạng thái thiết lập một phần của nó.

0

Không có câu trả lời cắt và sấy khô. Tuy nhiên, hãy nhớ rằng tối ưu hóa sớm là xấu. Trong Cocoa trên Mac hoặc trên iPhone, việc sử dụng các trình truy cập/thuộc tính được yêu cầu phải tuân thủ KVO. Sự phù hợp của KVO là cần thiết cho dữ liệu cốt lõi và các ràng buộc Cocoa để hoạt động tự động. Trong dữ liệu cốt lõi, nó không chỉ cần thiết để đảm bảo KVO khi sửa đổi các thuộc tính, mà còn khi truy cập chúng. Nó cũng là tốt nhất để sử dụng accessors/properties khi bạn muốn đảm bảo hành vi quản lý bộ nhớ tài sản, đó là để nói, luôn luôn khi thiết lập một ivar sử dụng ký hiệu setter hoặc dot, và tùy thuộc vào mô hình quản lý bộ nhớ bạn làm theo , luôn luôn sử dụng accessors/tài sản khi nhận được một ivar.

Có một số mẫu quản lý bộ nhớ khác nhau. Tất cả những người không bị hỏng đảm bảo rằng một đối tượng được trả về bởi một người truy cập sẽ tồn tại đến ít nhất là kết thúc của phạm vi autorelease hiện hành. Có nghĩa là, hoặc đối tượng được giữ lại một cách rõ ràng và tự động phát hiện trong phạm vi tự động phát hiện hành. Phương pháp được Apple khuyến cáo thực hiện điều này một cách rõ ràng trong bộ thu thập:

- (id)foo {return [[foo retain] autorelease]; } 
- (void)setFoo:(id)aFoo { 
    if(! [aFoo isEqual:foo]) { 
    [foo release]; 
    foo = [aFoo retain]; 
    } 
} 

Nó ngụ ý rằng đó là mẫu họ làm theo trong bộ tiếp cận tổng hợp của chúng. Cá nhân, tôi muốn tự động trả lại trong setter:

- (id)foo {return foo;} 
- (void)setFoo:(id)aFoo { 
    [foo autorelease]; 
    foo = [aFoo retain]; 
} 

Điều này tự động lấy lại giá trị cũ trước khi thay thế bằng giá trị mới. Điều này có tác dụng chính xác giống như giữ lại và tự động phát hiện trong bộ khởi động, nhưng yêu cầu đối tượng chỉ được thêm vào một nhóm tự động phát một lần. Hầu hết thời gian nó có một số lượng giữ lại của một và không phải là autoreleased, vì vậy nó sẽ không đi bất cứ nơi nào không có vấn đề gì xảy ra. Nếu thuộc tính được thay thế trong một số mã vẫn đang giữ nó (chẳng hạn như trong một cuộc gọi lại đại biểu), nó sẽ không biến mất khỏi nó. Điều này có nghĩa là việc sử dụng accessors/properties sẽ cho bạn sự tự tin rằng các đối tượng của bạn sẽ xung quanh miễn là bạn cần chúng mà không có một số phần khác của mã giải phóng chúng từ bên dưới bạn.

Lý do cuối cùng và tốt nhất để luôn sử dụng accessors/properties là làm cho một giả thiết ít hơn cho mỗi thuộc tính: rằng có một ivar cơ bản cho thuộc tính đó và có cùng tên (tôi đoán đó là hai giả định) . Có lẽ trong tương lai bạn sẽ muốn thay thế một cây ngà với một người truy cập có nguồn gốc. Ký hiệu thuộc tính sẽ vẫn hoạt động. Có lẽ bạn muốn đặt lại tên cho ngà voi; tài sản sẽ vẫn hoạt động. May mắn thay, tái cấu trúc trong Xcode thường có thể được dựa vào, nhưng tại sao thậm chí còn bận tâm?

Điểm của lập trình hướng đối tượng là sử dụng các giao diện được xác định trên lớp. Không có lý do chính đáng (mặc dù có rất nhiều lý do thành kiến ​​và hợp lý hóa) cho một lớp học bỏ qua giao diện riêng của nó. Mỗi phương pháp ngoại trừ chính người truy cập nên, trong trường hợp chung, đối xử với đối tượng như là bất khả xâm phạm và trạng thái nội bộ của nó là riêng tư. Viết mọi phương thức như thể nó nằm trong một danh mục hoặc trên một phân lớp phụ, và coi ivars là trạng thái riêng, trừ khi thiết kế cụ thể cần trực tiếp bạn làm khác. Có rất nhiều lý do chính đáng để truy cập trực tiếp vào ivars, nhưng chúng được xác định theo từng trường hợp cụ thể.

+0

Phương thức getter/setter của bạn không giống với Apple. Getter của bạn về cơ bản là một trong những bạn muốn sử dụng cho một tài sản "gán" và setter là cho một "giữ lại" tài sản. Tôi chắc chắn rằng nó hoạt động phần lớn thời gian nhưng tôi nghĩ rằng nó sẽ trở nên bất ngờ nếu bạn bắt đầu sử dụng các bể tự động của riêng bạn. Tốt nhất để gắn bó với các quy ước được sử dụng trong phần còn lại của Cocoa. –