Chính xác thì @synthesize làm gì?


148

Tôi đã thấy đoạn mã sau:

//example.h
MKMapView * mapView1;
@property (nonatomic, retain) MKMapView * mapView;

//example.m
@synthesize mapView = mapView1

Mối quan hệ giữa mapViewvà là mapView1gì? Nó tạo ra một setgetphương pháp cho mapView1?


1
Cập nhật: nhưng với bộ công cụ mới nhất @synthesize hiện không bao giờ cần thiết. Xem câu trả lời cho câu hỏi tràn ngăn xếp khác .
Ali Beadle

Câu trả lời:


228

Trong ví dụ của bạn, mapView1là một biến đối tượng (ivar), một phần lưu trữ bộ nhớ thuộc về một thể hiện của lớp được định nghĩa trong example.hexample.m. mapViewlà tên của một tài sản . Thuộc tính là thuộc tính của một đối tượng có thể được đọc hoặc đặt bằng cách sử dụng ký hiệu dấu chấm : myObject.mapView. Một tài sản không được dựa trên một Ivar, nhưng hầu hết tài sản này. Các @propertytuyên bố đơn giản là nói với thế giới rằng có một tài sản được gọi mapView.

@synthesize mapView = mapView1;

Dòng này báo cho trình biên dịch tạo một setter và getter cho mapView, và họ nên sử dụng ivar được gọi mapView1. Không có = mapView1phần này, trình biên dịch sẽ cho rằng thuộc tính và ivar có cùng tên. (Trong trường hợp này, điều đó sẽ tạo ra lỗi trình biên dịch, vì không có lệnh gọi ngà mapView.)

Kết quả của @synthesizetuyên bố này tương tự như nếu bạn đã tự thêm mã này:

-(MKMapView *)mapView
{
   return mapView1;
}

-(void)setMapView:(MKMapView *)newMapView
{
  if (newMapView != mapView1)
  {
    [mapView1 release];
    mapView1 = [newMapView retain];
  }
}

Nếu bạn tự thêm mã đó vào lớp, bạn có thể thay thế @synthesizecâu lệnh bằng

@dynamic mapView;

Điều chính là để có một sự phân biệt khái niệm rất rõ ràng giữa ngà voi và tài sản. Họ thực sự là hai khái niệm rất khác nhau.


31

@synthesize tạo một getter và setter cho biến.

Điều này cho phép bạn chỉ định một số thuộc tính cho các biến của mình và khi bạn thuộc tính đó cho @synthesizebiến bạn tạo getter và setter cho biến đó.

Tên thuộc tính có thể giống như tên biến. Đôi khi người ta muốn nó phải khác nhau để sử dụng nó trong inithoặc deallochoặc khi các tham số được truyền với tên giống nhau biến của.


16

Từ tài liệu :

Bạn sử dụng từ khóa @synthesize để nói với trình biên dịch rằng nó sẽ tổng hợp các phương thức setter và / hoặc getter cho thuộc tính nếu bạn không cung cấp chúng trong khối @im THỰCation.


8

Khi tôi gặp vấn đề này khi chỉnh sửa mã kế thừa, tôi muốn ghi chú thêm vào các câu trả lời hiện có mà người ta cần phải biết.

Ngay cả với phiên bản trình biên dịch mới hơn, đôi khi nó cũng tạo ra sự khác biệt nếu bạn bỏ qua @synthesize propertyNamehoặc không .

Trong trường hợp bạn khai báo một biến đối tượng mà không gạch dưới trong khi vẫn tổng hợp nó, chẳng hạn như:

Tiêu đề:

@interface SomeClass : NSObject {
   int someInt;
}
@property int someInt;
@end

Thực hiện:

@implementation SomeClass
@synthesize someInt;
@end

self.someIntsẽ truy cập cùng một biến như someInt. Không sử dụng dấu gạch dưới hàng đầu cho ivars không tuân theo các quy ước đặt tên nhưng tôi đã gặp phải tình huống phải đọc và sửa đổi mã đó.

Nhưng nếu bây giờ bạn nghĩ "Này, @synthesize không còn quan trọng nữa vì chúng tôi sử dụng trình biên dịch mới hơn" thì bạn đã nhầm! Lớp của bạn sau đó sẽ có hai ngà , cụ thể là someIntcộng với một _someIntbiến tự phát. Do đó self.someIntsomeIntsẽ không giải quyết các biến tương tự nữa. Nếu bạn không mong đợi những hành vi như tôi đã làm, điều này có thể khiến bạn đau đầu để tìm hiểu.


"đồng bộ hóa"! = "tổng hợp"?
jameshfisher

Vâng, đây là 2 khái niệm khác nhau. @synchronizelà một chỉ thị về cách đồng bộ hóa các luồng khi truy cập thuộc tính và @synthesizeđể ràng buộc thuộc tính với một biến thể hiện thông qua getters và setters.
Lars Blumberg

1
Nhận xét của jameshfisher có ý cảnh báo bạn rằng bạn đã nhầm lẫn đồng bộ hóa và tổng hợp trong câu trả lời của mình. Bạn sử dụng hai thay thế cho nhau.
Maple

1
Cảm ơn vì đã khiến tôi nhận ra điều đó! Tôi hoàn toàn giám sát rằng, tôi đã cập nhật câu trả lời để không sử dụng từ khóa @synyncize không tồn tại.
Lars Blumberg

Trong trường hợp đó, xcode 10 sẽ cảnh báo về vấn đề : Autosynthesized property 'someInt' will use synthesized instance variable '_someInt', not existing instance variable 'someInt'. (Tôi không biết phiên bản nào của xcode cảnh báo này đã được thêm vào.)
zwcloud

7

Theo tài liệu apple @Synthesize chỉ được sử dụng để đổi tên các biến thể hiện. Ví dụ

@property NSString *str;

@synthesize str = str2; 

Bây giờ trong lớp bạn không thể sử dụng _strvì dòng trên đã đổi tên biến thể hiện thànhstr2

@property cho phép các đối tượng được sử dụng bởi các đối tượng trong các lớp khác hoặc nói cách khác làm cho đối tượng được công khai.


3
Rõ ràng, bắt đầu với Xcode 4.4, Clang cung cấp hỗ trợ cho quá trình tự động tổng hợp các thuộc tính được khai báo. Vì vậy, @synthesize không còn cần thiết cho hầu hết các trường hợp. Xem useyourloaf.com/blog/2012/08/01/ khăn
huyz

5

Khi bạn tạo một thuộc tính trong @interface, thuộc tính đó sẽ được tự động quay lại bởi một biến đối tượng có tên là _propertyName. Vì vậy, khi bạn tạo một thuộc tính có tên là FirstName, đằng sau trình biên dịch cảnh sẽ tạo một biến đối tượng có tên là _firstName theo mặc định. Trình biên dịch cũng sẽ tạo phương thức getter và setter cho bạn (ví dụ FirstName, setFirstName).

Bây giờ khi bạn tổng hợp thuộc tính bằng @synthesize FirstName, bạn chỉ cần nói cho trình biên dịch đổi tên biến đối tượng của tôi (_firstName) bằng FirstName. Nếu bạn muốn đổi tên biến đối tượng được sao lưu của mình bằng tên khác, bạn có thể chỉ định tên khác trong khi tổng hợp tên thuộc tính (ví dụ: @synthesize firstName = myFirstName), bằng cách này, thuộc tính của bạn được sao lưu bởi một biến đối tượng có tên là myFirstname.

Vì vậy, trong ngắn hạn, hầu hết thời gian @synthesize được sử dụng để đổi tên biến đối tượng của bạn được sao lưu bởi thuộc tính của bạn.


2

Xem tài liệu táo

Về cơ bản, tổng hợp tạo ra một phương thức setMapView và mapView để thiết lập và nhận mapView1


2

Nó tạo getter và setter cho đối tượng của bạn. Bạn có thể truy cập với một cái gì đó như thế này:

MKMapView* m = object.mapView;

hoặc là

object.mapView = someMapViewObject

mapView1 là tên của ivar trong lớp, mapView là tên của (các) phương thức getter / setter.

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.