@synthesize ทำอะไรกันแน่?


148

ฉันเห็นโค้ดต่อไปนี้แล้ว:

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

//example.m
@synthesize mapView = mapView1

ความสัมพันธ์ระหว่างmapViewและmapView1คืออะไร? มันสร้างsetและgetวิธีการmapView1หรือไม่?


1
อัปเดต: แต่ด้วยชุดเครื่องมือล่าสุด @synthesize ตอนนี้แทบไม่จำเป็นเลย ดูคำตอบอื่น ๆ Stack มากเกินคำถาม
Ali Beadle

คำตอบ:


228

ในตัวอย่างของคุณmapView1เป็นตัวแปรเช่น (Ivar), ชิ้นส่วนของหน่วยความจำที่เป็นตัวอย่างของการเรียนที่กำหนดไว้ในและexample.h เป็นชื่อของที่คุณสมบัติ คุณสมบัติเป็นคุณสมบัติของวัตถุที่สามารถอ่านหรือตั้งค่าการใช้สัญกรณ์จุดนี้: คุณสมบัติไม่จำเป็นต้องอิงจาก ivar แต่คุณสมบัติส่วนใหญ่เป็น ประกาศเพียงแค่บอกโลกว่ามีคุณสมบัติที่เรียกว่าexample.mmapViewmyObject.mapView@propertymapView

@synthesize mapView = mapView1;

บรรทัดนี้จะบอกคอมไพเลอร์เพื่อสร้างหมาและทะเยอทะยานสำหรับmapViewและที่พวกเขาควรจะใช้ Ivar mapView1ที่เรียกว่า โดยไม่ต้อง= mapView1มีส่วนร่วมคอมไพเลอร์จะคิดว่าทรัพย์สินและ Ivar มีชื่อเดียวกัน (ในกรณีนี้นั่นจะทำให้เกิดข้อผิดพลาดของคอมไพเลอร์เนื่องจากไม่มี ivar ที่เรียกว่าmapView)

ผลลัพธ์ของ@synthesizeข้อความนี้คล้ายกับว่าคุณได้เพิ่มรหัสนี้ด้วยตัวเอง:

-(MKMapView *)mapView
{
   return mapView1;
}

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

หากคุณเพิ่มรหัสนั้นในชั้นเรียนด้วยตัวเองคุณสามารถแทนที่@synthesizeคำสั่งด้วย

@dynamic mapView;

สิ่งสำคัญคือการมีความแตกต่างทางแนวคิดที่ชัดเจนระหว่างไอวอรี่และคุณสมบัติ พวกเขาเป็นแนวคิดที่แตกต่างกันสองอย่างจริงๆ


31

@synthesize สร้าง getter และ setter สำหรับตัวแปร

สิ่งนี้ช่วยให้คุณสามารถระบุคุณสมบัติบางอย่างสำหรับตัวแปรของคุณและเมื่อคุณใช้@synthesizeคุณสมบัตินั้นกับตัวแปรที่คุณสร้างขึ้นมาและตัวตั้งค่าสำหรับตัวแปรนั้น

ชื่อคุณสมบัติสามารถเหมือนกับชื่อตัวแปร บางคนต้องการให้เป็นที่แตกต่างกันเพื่อให้เป็นที่จะใช้ในinitหรือdeallocหรือเมื่อพารามิเตอร์ถูกส่งผ่านไปที่มีชื่อตัวแปรเดียวกัน


16

จากเอกสาร :

คุณใช้คีย์เวิร์ด @synthesize เพื่อบอกคอมไพเลอร์ว่าควรสังเคราะห์เมธอด setter และ / หรือ getter สำหรับคุณสมบัติหากคุณไม่ได้ระบุไว้ในบล็อก @implementation


8

เมื่อฉันพบปัญหานี้เมื่อแก้ไขรหัสดั้งเดิมฉันต้องการทำบันทึกเพิ่มเติมสำหรับคำตอบที่มีอยู่ซึ่งจำเป็นต้องทราบ

แม้จะมีคอมไพเลอร์เวอร์ชั่นใหม่กว่าบางครั้งมันก็สามารถสร้างความแตกต่างได้หากคุณเว้นไว้@synthesize propertyNameหรือไม่หรือไม่

ในกรณีที่คุณประกาศตัวแปรอินสแตนซ์โดยไม่ต้องขีดเส้นใต้ในขณะที่ยังคงทำการสังเคราะห์เช่น:

หัวข้อ:

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

การดำเนินงาน:

@implementation SomeClass
@synthesize someInt;
@end

self.someInt จะเข้าถึงตัวแปรเดียวกับ someIntจะเข้าถึงตัวแปรเดียวกับการไม่ใช้ขีดเส้นใต้ชั้นนำสำหรับ ivars ไม่เป็นไปตามอนุสัญญาการตั้งชื่อ แต่ฉันเพิ่งเข้ามาในสถานการณ์ที่ฉันต้องอ่านและแก้ไขรหัสดังกล่าว

แต่ถ้าคุณคิดว่า"เฮ้ @ ซินธิไซซ์ไม่สำคัญอีกต่อไปเมื่อเราใช้คอมไพเลอร์ใหม่กว่า"คุณคิดผิด! คลาสของคุณจะส่งผลให้มีสอง ivarsคือsomeIntบวกกับ_someIntตัวแปรที่สร้างอัตโนมัติ ดังนั้นself.someIntและsomeIntจะไม่แก้ไขตัวแปรเดียวกันอีกต่อไป หากคุณไม่คาดหวังพฤติกรรมเช่นนี้เพราะฉันทำสิ่งนี้อาจทำให้คุณปวดหัวในการค้นหา


"ประสาน"! = "สังเคราะห์"?
jameshfisher

ใช่เหล่านี้เป็นแนวคิดที่แตกต่าง 2 @synchronizeเป็นคำสั่งสำหรับวิธีการซิงโครไนซ์เธรดเมื่อเข้าถึงคุณสมบัติและใช้@synthesizeสำหรับเชื่อมโยงคุณสมบัติกับตัวแปรอินสแตนซ์ผ่าน getters และ setters
Lars Blumberg

1
ความคิดเห็นของ jameshfisher มีไว้เพื่อเตือนคุณว่าคุณสับสนประสานและสังเคราะห์ในคำตอบของคุณ คุณใช้ทั้งสองสลับกันได้
เมเปิ้ล

1
ขอบคุณที่ทำให้ฉันตระหนักถึงสิ่งนั้น! ฉันดูแลอย่างเต็มที่ฉันได้อัปเดตคำตอบเพื่อไม่ใช้คำหลัก @synchronize ที่ไม่มีอยู่
Lars Blumberg

ในกรณีที่ Xcode 10 Autosynthesized property 'someInt' will use synthesized instance variable '_someInt', not existing instance variable 'someInt'จะเตือนเกี่ยวกับปัญหานี้ (ผมไม่ทราบว่าในรุ่นของ Xcode คำเตือนนี้ถูกเพิ่มเข้ามา.)
zwcloud

7

ตามเอกสารของApple @Synthesizeใช้เพื่อเปลี่ยนชื่อตัวแปรอินสแตนซ์เท่านั้น ตัวอย่างเช่น

@property NSString *str;

@synthesize str = str2; 

ตอนนี้ในชั้นเรียนคุณไม่สามารถใช้_strเป็นบรรทัดด้านบนได้เปลี่ยนชื่อตัวแปรเช่นstr2

@property อนุญาตให้วัตถุถูกใช้โดยวัตถุในคลาสอื่นหรือในคำอื่น ๆ ทำให้วัตถุเป็นสาธารณะ


3
เห็นได้ชัดว่าเริ่มต้นด้วย Xcode 4.4 Clang ให้การสนับสนุนการสังเคราะห์คุณสมบัติที่ประกาศโดยอัตโนมัติ ดังนั้น @synthesize ไม่จำเป็นสำหรับกรณีส่วนใหญ่อีกต่อไป ดูuseyourloaf.com/blog/2012/08/01/…
huyz

5

เมื่อคุณสร้างพร็อพเพอร์ตี้ใน @interface พร็อพเพอร์ตี้นั้นจะกลับมาโดยอัตโนมัติด้วยตัวแปรอินสแตนซ์ชื่อ _propertyName ดังนั้นเมื่อคุณสร้างคุณสมบัติชื่อ firstName ด้านหลังคอมไพเลอร์ฉากจะสร้างตัวแปรอินสแตนซ์ชื่อ _firstName โดยค่าเริ่มต้น คอมไพเลอร์จะสร้างเมธอด getter และ setter ให้คุณ (เช่น firstName, setFirstName)

ตอนนี้เมื่อคุณสังเคราะห์คุณสมบัติโดย @synthesize ชื่อแรกคุณเพียงแค่บอกคอมไพเลอร์เปลี่ยนชื่อตัวแปรอินสแตนซ์ของฉัน (_firstName) โดย FirstName หากคุณต้องการเปลี่ยนชื่อตัวแปรอินสแตนซ์สำรองของคุณด้วยชื่ออื่นคุณสามารถกำหนดชื่อที่แตกต่างได้ในขณะที่ทำการสังเคราะห์ชื่อคุณสมบัติ (เช่น @synthesize firstName = myFirstName) โดยการทำเช่นนี้คุณสมบัติของคุณจะถูกสำรองข้อมูลโดยตัวแปรอินสแตนซ์ชื่อ myFirstname

ดังนั้นโดยย่อส่วนใหญ่เวลา @synthesize ใช้ในการเปลี่ยนชื่อตัวแปรอินสแตนซ์ของคุณสำรองโดยคุณสมบัติของคุณ



2

มันสร้างทะเยอทะยานและ setter สำหรับวัตถุของคุณ คุณสามารถเข้าถึงด้วยสิ่งนี้:

MKMapView* m = object.mapView;

หรือ

object.mapView = someMapViewObject

mapView1 เป็นชื่อของ ivar ในคลาส mapView เป็นชื่อของเมธอด getter / setter

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.