2011-09-30 32 views
20

Tôi muốn tạo ra một phương pháp như thế này:Mục tiêu-c: con trỏ kép cho thuộc tính không được phép?

- (void) checkAndUpdateStringProperty: (NSString **) property{ 
    if (...) 
     *property = @"whatever"; 
} 

Tôi muốn sử dụng để vượt qua trong một tài sản cho cùng lớp:

- (void) somewhereElse{ 
     .... 
     [self checkAndUpdateStringProperty: &self.productName]; 
} 

Nhưng điều này mang lại một lỗi cú pháp, nói rằng "Địa chỉ của biểu thức thuộc tính được yêu cầu ". Có lý do gì không? Nếu tôi thay thế các tài sản lớp với một biến địa phương, nó hoạt động tốt:

- (void) somewhereElse{ 
     NSString *name = nil; 
     [self checkAndUpdateStringProperty: &name]; 
} 

Trả lời

26

Thuộc tính chỉ được truy cập thông qua các phương thức getter và setter, ngoại trừ khởi tạo và deinitializing chúng trong các phương thức initdealloc của đối tượng (khi đối tượng không ở trạng thái hoàn toàn nhất quán) - truy cập chúng cách đánh bại mục đích của họ và không tôn trọng các thuộc tính của họ (retain, copy, v.v.).

Lý do tại sao nó không biên dịch là vì trình truy cập thuộc tính là cú pháp đường cho các cuộc gọi phương thức và bạn không thể lấy địa chỉ của giá trị trả về của một phương thức. self.productName giống hệt với [self productName]&[self productName] không có ý nghĩa.

Nếu bạn thực sự muốn làm điều này, đừng làm điều đó với một thuộc tính, hãy làm điều đó chỉ với một biến thông thường (chẳng hạn như biến cục bộ hoặc ivar) và ghi lại ngữ nghĩa của hàm của bạn: chức năng gọi điện thoại cần phải release đối tượng được trả về? Ví dụ, các phương pháp khác nhau của Apple lấy NSError** chỉ định rằng đối tượng lỗi được trả về, nếu có, là một đối tượng được tự động phát hành, vì vậy bạn không nên tự mình release trừ khi bạn cũng retain nó.

+1

Ngoại lệ để truy cập trực tiếp các thuộc tính của ivars trong 'init' và' dealloc' trong đó lớp không ở dạng hoàn chỉnh và bất kỳ tác dụng phụ nào cũng có thể gây ra vấn đề. – zaph

+0

Điểm tốt, được cập nhật. –

+2

Cảm ơn. Trên thực tế đã tìm ra rằng (vì đây là một NSManagedObject), tôi có thể chuyển vào tên của thuộc tính và truy cập giá trị bằng cách sử dụng valueForKey, và đặt nó bên trong phương thức 'check' bằng cách sử dụng setValue: forKey: Không cần phải thực hiện phép đo hai con trỏ . –

7

Có rất ít nơi trong API của Apple rằng một giá trị được thông qua trong thời trang này, một trong những chính là NSError. Nó thực sự là tốt nhất để chỉ trả lại kết quả. Nếu bạn có tham số tham chiếu thì quy tắc chung của Apple là nó phải là tham số cuối cùng mà tên phương thức bắt đầu bằng "get" như trong getCheckAndUpdateStringProperty.

Nhưng bạn có thể làm điều đó, nó không chỉ là những gì chúng tôi đang sử dụng để.

Lỗi bạn đang thấy là self.productName thực sự viết tắt cho cuộc gọi phương thức: [self productName] do đó &self.productName được hiểu là &[self productName].

Hơn nữa trong trường hợp này nếu productName là @property với thuộc tính giữ lại, việc tính tham chiếu sẽ bị đảo ngược.

5

Nếu bạn đang thực sự cẩn thận về các thuộc tính sở hữu, bạn có thể khắc phục vấn đề này bằng cách nhìn chằm chằm vào những điều sau:

[self property] 

vs:

self.property 

vs:

self->property 

Khi bạn hiểu rõ sự khác biệt, bạn có thể thử điều này:

[self checkAndUpdateStringProperty: &self->productName] 

Lưu ý việc sử dụng: ->

tôi sử dụng tất cả thời gian khi các thuộc tính tài sản là assign và khi nó là một nguyên thủy, không loại đối tượng: (float, int,. ..)

+0

'self-> productName' là một ý tưởng thực sự tồi tệ, nó phá vỡ đóng gói. – zaph

0

tạo thuộc tính của biến đó, mà bạn muốn truy cập trong một lớp khác (@property (mạnh, nonatomic);) và sau đó tổng hợp nó .... (@synthesize;) và sau đó truy cập qua tên đối tượng của lớp đó, nơi bạn xác định thuộc tính và tổng hợp nó .....

+0

Định dạng câu trả lời của bạn để làm rõ. – NAZIK

0

Tôi muốn làm điều này bằng cách sử dụng bộ chọn để thay thế (bạn sẽ phải chuyển nó sang chức năng ac để làm cho nó làm việc mà không cảnh báo (xem here):

- (void) checkAndUpdateStringProperty: (SEL)setter { 
    if (...) 
    IMP imp = [self methodForSelector:setter]; 
    void (*func)(id, SEL, id) = (void *)imp; 
    func(self, setter, @"whatever"); 
} 

Sử dụng này để vượt qua trong các bộ chọn cho cùng một lớp:

- (void) somewhereElse{ 
     .... 
     [self checkAndUpdateStringProperty:@selector(setProductName:)]; 
} 
Các vấn đề liên quan