Làm thế nào để một dấu gạch dưới trước một biến trong lớp mục tiêu ca cao-c hoạt động?


157

Tôi đã thấy trong một vài ví dụ trên iPhone rằng các thuộc tính đã sử dụng dấu gạch dưới _ phía trước biến. Có ai biết điều này? Hoặc làm thế nào nó hoạt động?

Một tệp giao diện tôi đang sử dụng trông như:

@interface MissionCell : UITableViewCell {
    Mission *_mission;
    UILabel *_missionName;
}

@property (nonatomic, retain) UILabel *missionName;

- (Mission *)mission;

Tôi không chắc chính xác những gì ở trên nhưng khi tôi cố gắng đặt tên nhiệm vụ như sau:

aMission.missionName = missionName;

Tôi nhận được lỗi:

yêu cầu thành viên 'MissionName' trong một cái gì đó không phải là cấu trúc hoặc liên minh

Câu trả lời:


97

Nếu bạn sử dụng tiền tố gạch dưới cho ivars của bạn (không có gì khác hơn một quy ước chung, nhưng là một quy tắc hữu ích), thì bạn cần phải thực hiện thêm 1 điều để trình truy cập được tạo tự động (cho thuộc tính) biết nên sử dụng ivar nào. Cụ thể, trong tệp thực hiện của bạn, bạn synthesizesẽ trông như thế này:

@synthesize missionName = _missionName;

Tổng quát hơn, đây là:

@synthesize propertyName = _ivarName;

78
với các thuộc tính tự động tổng hợp, điều này không còn cần thiết nữa. Xcode tổng hợp một xxxx @property với một chiếc ngà có tên _xxxx đằng sau hậu trường. Khéo léo.
Tìm hiểuCocos2D

@ Tìm hiểuCocos2D Xin chào! Một người mới chơi iOS ở đây và có vài điều tôi cần làm rõ. Trong tất cả thời gian này, những gì tôi đã làm là khai báo propertytệp .h và trong .m fie tôi truy cập nó bằng cách sử dụng selfnhư vậy , self.someProperty. Đây có phải là hướng đi đúng? Hoặc tôi nên sử dụng ivars trong mã?
Isuru

thiết lập ivar không chạy trình thiết lập thuộc tính - bạn quyết định xem đó có phải là ý tưởng tốt hay không cho từng trường hợp cụ thể
LearnCocos2D

Câu hỏi của Noob: tại sao không sử dụng ngà voi trực tiếp? Tại sao tôi nên khai báo một var riêng để giữ ivar?
Allen

1
@ ALLen, nếu tôi hiểu chính xác câu hỏi của bạn: var riêng biệt mà bạn khai báo là một con trỏ tới biến thực. Điều này rất quan trọng vì một vài lý do (mà tôi biết) Thứ nhất, khi bạn chuyển một con trỏ vào một hàm bạn không sao chép giá trị của nó. Bạn chỉ cần nói cho hàm biết nơi tìm giá trị để sử dụng. Điều này giúp giữ cho bộ nhớ đã sử dụng của bạn ở mức thấp (và cũng giúp phân bổ và giải quyết bộ nhớ, điều này rất quan trọng trong trường hợp không có 'bộ sưu tập rác' mà bạn sẽ tìm thấy trong Java)
David Sigley

18

Nó chỉ là một quy ước cho khả năng đọc, nó không làm gì đặc biệt cho trình biên dịch. Bạn sẽ thấy mọi người sử dụng nó trên các biến cá thể và tên phương thức riêng. Apple thực sự khuyên bạn không nên sử dụng dấu gạch dưới (nếu bạn không cẩn thận, bạn có thể ghi đè lên thứ gì đó trong siêu lớp của bạn), nhưng bạn không nên cảm thấy tồi tệ khi bỏ qua lời khuyên đó. :)


19
Theo những gì tôi hiểu, Apple khuyên bạn không nên sử dụng tiền tố gạch dưới cho tên phương thức (họ bảo lưu rằng đó là quy ước cho các phương thức riêng tư), nhưng họ không có bất kỳ khuyến nghị nào như vậy về tên biến thể hiện.
Kelan

9
@Kelan Trên thực tế, Apple khuyến khích làm như vậy : "Thông thường, bạn không nên truy cập trực tiếp các biến thể hiện, thay vào đó bạn nên sử dụng các phương thức truy cập (bạn thực hiện truy cập các biến đối tượng trực tiếp trong các phương thức init và dealloc). tên biến có dấu gạch dưới (_), ví dụ: \ @im THỰCation MyClass {BOOL _showsTitle;} "
dmirkitanov

Tôi thực sự không nghĩ Apple khuyến khích chúng tôi làm như vậy, vì tất cả các mã mẫu của riêng họ trong Thư viện nhà phát triển iOS không có ( ) trong đó. Apple cũng nói rằng họ đã bảo lưu nó, điều đó có nghĩa là họ sử dụng nó trong nội bộ cho các khung riêng của họ như UIKit, v.v ... Đó là lý do tại sao chúng ta không nên bất cẩn sử dụng nó. Nhưng tôi thấy rằng, trong liên kết bạn đã cung cấp @kelan. Họ thực sự nói trong "lịch sử sửa đổi" rằng nó "phù hợp" để sử dụng ( ). Tôi giải thích là chúng ta "có thể" sử dụng nó nếu chúng ta muốn.
WYS

Tài liệu của Apple nói rằng không sử dụng tiền tố gạch dưới cho tên phương thức có ở đây .
ThomasW

9

Mục đích hữu ích duy nhất tôi đã thấy là phân biệt giữa các biến cục bộ và biến thành viên như đã nêu ở trên, nhưng nó không phải là một quy ước cần thiết. Khi được ghép nối với một @property, nó làm tăng tính dài dòng của các câu lệnh tổng hợp - @synthesize missionName = _missionName;và xấu ở mọi nơi.

Thay vì sử dụng dấu gạch dưới, chỉ cần sử dụng tên biến mô tả trong các phương thức không xung đột. Khi chúng phải xung đột, tên biến trong phương thức sẽ bị gạch dưới, không phải là biến thành viên có thể được sử dụng bởi nhiều phương thức . Điểm chung duy nhất này hữu ích là trong một setter hoặc trong một phương thức init. Ngoài ra, nó sẽ làm cho tuyên bố @synthesize ngắn gọn hơn.

-(void)setMyString:(NSString*)_myString
{
    myString = _myString;
}

Chỉnh sửa: Với tính năng biên dịch mới nhất của tổng hợp tự động, bây giờ tôi sử dụng dấu gạch dưới cho ivar (trong trường hợp hiếm hoi tôi cần sử dụng ivar để phù hợp với những gì tự động tổng hợp.


Đó là cách khác xung quanh. biến riêng được nhấn mạnh. Các tài sản không. và whem tổng hợp chúng bạn cặp đôi chúng.
Justin

Đó chính xác là những gì tôi mô tả, ngoại trừ việc tôi gọi nó là "biến thành viên" thay vì "biến riêng".
Peter De Weese

Ôi! Đây là yêu cầu sự cố tự động tổng hợp, sẽ làm cho ivar _myString có nghĩa là trình thiết lập của bạn sẽ không hoạt động (vì sau đó nó sẽ không thể nói với ivar của bạn từ tham số phương thức).
geowar

Chính xác, đó là lý do tại sao tôi đã thêm chỉnh sửa vào cuối khi apple thêm tự động tổng hợp.
Peter De Weese

5

Nó thực sự không có nghĩa gì cả, nó chỉ là một quy ước mà một số người sử dụng để phân biệt các biến thành viên với các biến cục bộ.

Đối với lỗi, có vẻ như aMission có loại sai. Nó tuyên bố cái gì?


Nó phổ biến trong IDE với intellisense; nó sẽ làm cho các biến thành viên / mô đun / lớp của bạn hiển thị ở đầu danh sách. Một tiền tố phổ biến khác là "m_"
STW

1
nếu nó không có nghĩa gì thì làm sao bạn có thể chuyển đổi qua lại giữa _missionName và MissionName như trong ví dụ của tôi ở trên? Tuyên bố của tôi trông giống như: Nhiệm vụ * aMission = [[Phân bổ nhiệm vụ] init]; aMission.missionName = @ "một nhiệm vụ";
Atma

1
Một là một biến đối tượng và cái còn lại là một thuộc tính. Bạn không thể truy cập các biến đối tượng với cú pháp như aMission.missionName, vì cú pháp đó không hoạt động với các con trỏ.
Chuck

Ngoài ra, lưu ý rằng bạn đang cố gắng hoạt động trên một đối tượng Mission, nhưng giao diện bạn đã đăng với thuộc tính MissionName là MissionCell.
tổ chức

2

Điều này chỉ dành cho quy ước đặt tên của các thuộc tính tổng hợp.

Khi bạn tổng hợp các biến trong tệp .m, Xcode sẽ tự động cung cấp cho bạn trí thông minh có thể thay đổi.


1

Việc có dấu gạch dưới không chỉ giúp giải quyết các ngà của bạn mà không cần sử dụng cú pháp self.member mà nó còn giúp mã của bạn dễ đọc hơn vì bạn biết khi nào một biến là một ivar (vì tiền tố gạch dưới của nó) hoặc đối số thành viên (không có dấu gạch dưới ).

Thí dụ:

- (void) displayImage: (UIImage *) image {

    if (image != nil) {
        // Display the passed image...
        [_imageView setImage: image];
    } else {
        // fall back on the default image...
        [_imageView setImage: _image];
    }
}

Trong ví dụ này, thật tuyệt khi thấy một so sánh về việc sử dụng self.image (hoặc [hình ảnh bản thân]). Khi nào thì tốt hơn để sử dụng self.image và khi nào thì tốt hơn khi sử dụng _image?
Boeckm

2
@Boeckm: Nói chung, bạn nên sử dụng self.image, truy cập vào tài sản. Lần duy nhất bạn nên truy cập vào biến thể hiện, _imagetrực tiếp là trong initcác phương thức và deallocphương thức, khi gọi bất kỳ phương thức nào khác có thể có rủi ro (vì đối tượng được khởi tạo một nửa hoặc được giải quyết một nửa).
Peter Hosey

1

Đây có vẻ là mục "chính" cho các câu hỏi về self.variableName so với _variablename. Điều khiến tôi cho một vòng lặp là trong .h, tôi đã có:

...
@interface myClass : parentClass {
className *variableName;    // Note lack of _
}

@property (strong, nonatomic) className  *variableName;
...

Điều này dẫn đến self.variableName và _variableName là hai biến khác biệt trong .m. Điều tôi cần là:

...
@interface myClass : parentClass {
className *_variableName;    // Note presence of _
}

@property (strong, nonatomic) className  *variableName;
...

Sau đó, trong lớp '.m, self.variableName và _variableName là tương đương.

Điều tôi vẫn chưa rõ là tại sao nhiều ví dụ vẫn hoạt động, thậm chí khó khăn điều này không được thực hiện.

cá đuối


0

thay vì gạch dưới, bạn có thể sử dụng tên self.variable hoặc bạn có thể tổng hợp biến để sử dụng biến hoặc ổ cắm mà không gạch dưới.


2
nếu bạn chỉ cần biến trong cùng một lớp, chỉ cần khai báo nó trong tệp .m thì nó sẽ cho phép bạn gọi mà không cần tự cũng không gạch dưới
Ansal Antony

0

Thiếu từ các câu trả lời khác là việc sử dụng _variablesẽ ngăn bạn vô ý gõ variablevà truy cập vào ngà thay vì thuộc tính (được cho là có chủ đích).

Trình biên dịch sẽ buộc bạn sử dụng self.variablehoặc _variable. Sử dụng dấu gạch dưới làm cho nó không thể gõ variable, làm giảm lỗi lập trình.

- (void)fooMethod {

    // ERROR - "Use of undeclared identifier 'foo', did you mean '_foo'?"
    foo = @1;

    // So instead you must specifically choose to use the property or the ivar:

    // Property
    self.foo = @1;

    // Ivar
    _foo = @1;

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.