จะเกิดอะไรขึ้นเมื่อฉันตั้งค่าคุณสมบัติของวัตถุโดยใช้วิธี accessor

สมมติว่าฉันมีอ็อบเจ็กต์ชื่อ MyClass ซึ่งมีคุณสมบัติที่กำหนดเป็น @property (nonatomic, retain) NSString *foo; และฉันสังเคราะห์คุณสมบัตินั้น

จากนั้นในคลาสอื่น สมมติว่าตัวแทนแอปพลิเคชันฉันกำหนดสตริง (แต่อาจเป็นอะไรก็ได้) NSString *myString = [[NSString alloc] initWithString:@"Hi"]; และเรียกใช้อินสแตนซ์ของ MyClass: [myClass setFoo:myString];

เกิดอะไรขึ้นจริงๆ? การอ้างอิงไปยังพื้นที่ที่ได้รับการจัดสรรสำหรับ myString ได้รับการตั้งค่าหรือไม่ หรือได้รับสิ่งที่อยู่ในหน่วยความจำที่จัดสรรสำหรับ myString และตั้งค่าเป็นหน่วยความจำที่จัดสรรสำหรับ foo เนื่องจากฉันเรียก retain บน foo

และฉันต้องปล่อย myString ในตัวแทนแอปพลิเคชัน และฉันต้องปล่อย foo ใน MyClass เนื่องจากมันถูกเก็บไว้ แต่ฉันจะต้องปล่อยอีกครั้งหรือไม่เนื่องจากมีการกำหนดตัวแปร alloc'd อื่นให้กับมัน


person Josh Sherick    schedule 13.08.2011    source แหล่งที่มา


คำตอบ (3)


ทุกอย่างขึ้นอยู่กับวิธีการประกาศทรัพย์สิน เนื่องจากของคุณคือ (retain) มันจะเก็บตัวชี้ออบเจ็กต์เดิมไว้ และส่ง -retain โดยอัตโนมัติ เพื่อให้มั่นใจว่าสามารถเข้าถึงหน่วยความจำได้ ไม่ว่าผู้เรียกจะเก็บการอ้างอิงไว้หรือไม่ก็ตาม หากคุณใช้ (copy) มันจะส่ง -copy ซึ่งจะสร้างออบเจ็กต์ใหม่ซึ่งเป็นสำเนาของอันเก่า (โดยที่ออบเจ็กต์นั้นสอดคล้องกับ `NSCopying)

ทั้งหมดนี้เกิดขึ้นในการใช้งานอุปกรณ์เสริม ซึ่งโดยทั่วไปจะสร้างขึ้นสำหรับคุณเมื่อคุณใช้ @synthesize หากคุณนำไปใช้เอง อย่าลืมใช้พฤติกรรมที่ถูกต้อง!

person jtbandes    schedule 13.08.2011
comment
นั่นหมายความว่าถ้าฉันเปลี่ยน myString หรือ foo มันจะเปลี่ยนอันอื่นเนื่องจากจริงๆ แล้วเป็นเพียงการอ้างอิงถึงตัวแปรเดียวกัน - person Josh Sherick; 13.08.2011
comment
ประเภท — จำไว้ว่าคุณไม่สามารถเปลี่ยน NSString ได้ แต่เปลี่ยนได้เพียง NSMutableString เท่านั้น และคุณสมบัติ NSString มักจะเป็น (copy) อยู่แล้ว - person jtbandes; 13.08.2011
comment
ใช่. นี่ไม่ใช่ตัวอย่างจริง ฉันแค่พูดถึงวัตถุโดยทั่วไป ไม่ใช่สตริง บอกว่ามันเป็น nsmutablestring และฉันเปลี่ยนอันหนึ่ง มันจะเปลี่ยนอันอื่นไหม - person Josh Sherick; 13.08.2011
comment
ใช่ ถ้าไม่ใช่ (copy) ลองมัน! - person jtbandes; 13.08.2011

@synthesize โดยพื้นฐานแล้วจะสร้างสองวิธีให้คุณ ในกรณีของคุณทั้งสองวิธีจะคล้ายกับสิ่งนี้:

-(NSString*) foo;
{
    return foo; //synthesized ivar
}

-(void) setFoo:(NSString*)newValue;
{
    if(foo != newValue){
        [foo release];
        foo = [newValue retain];
    }
}

อย่างไรก็ตาม @synthesize จะไม่ปล่อยค่าใน dealloc ดังนั้นคุณต้องดำเนินการด้วยตนเอง

วัตถุใน Objective-C จะถือเป็นพอยน์เตอร์ ดังนั้นเมื่อคุณพูดว่า NSString* a = b; คุณไม่ได้คัดลอกออบเจ็กต์นั้นเอง คุณกำลังสร้างพอยน์เตอร์อีกตัวไปยังวัตถุนั้น คุณสมบัติสังเคราะห์ก็ไม่มีข้อยกเว้นในเรื่องนี้

person Tom Dalling    schedule 13.08.2011
comment
สิ่งนี้ถูกต้องสำหรับคุณสมบัติ (nonatomic) เท่านั้น ฉันเชื่อว่า :) - person jtbandes; 13.08.2011
comment
ใช่. มันจะแตกต่างออกไปเล็กน้อยถ้าคุณสมบัติในคำถามคืออะตอม - person Tom Dalling; 13.08.2011
comment
ซึ่งฉันเชื่อว่าทอมได้รวมคำเตือนไว้ที่ตอนต้นของคำตอบด้วย การนำวิธีการสังเคราะห์ไปใช้นั้นถูกต้องสำหรับคำหลักที่ OP ใช้ - person Perception; 13.08.2011
comment
ที่จริงแล้ว @synthesize foo; สร้างโค้ดเช่น: return [[foo retain] autorelease]; หากคุณสมบัติเป็นแบบอะตอมมิก ก็จะใส่การล็อกรอบโค้ดใน setFoo: ด้วย - person Rudy Velthuis; 13.08.2011
comment
FWIW คุณสมบัติสตริงมักจะประกาศเป็น (copy) จากนั้นจึงทำการคัดลอก - person Rudy Velthuis; 13.08.2011
comment
@Rudy Velthuis จริง ๆ แล้วมันไม่ได้ปล่อย ivar โดยอัตโนมัติจากวิธีการเข้าถึงแบบสังเคราะห์ - person Tom Dalling; 14.08.2011
comment
จากทะเยอทะยาน? คุณแน่ใจไหม? - person Rudy Velthuis; 14.08.2011
comment
ฉันจำได้ว่าเคยอ่านอะไรบางอย่างเกี่ยวกับเรื่องนี้มาได้สักพักแล้ว ดังนั้นฉันจึงทดสอบมันเมื่อ 5 นาทีที่แล้ว และไม่มีการเรียกการเผยแพร่อัตโนมัติ - person Tom Dalling; 14.08.2011

สิ่งที่เกิดขึ้นคือออบเจ็กต์ myString ชี้ให้นับจำนวนการคงไว้เพิ่มขึ้นหนึ่งเมื่อคุณทำ [myClass setFoo:myString];

เริ่มแรก เมื่อคุณจัดสรรสตริงและจัดเก็บข้อมูลอ้างอิงใน myString จำนวนการเก็บรักษาจะเป็น 1 การจัดเก็บไว้ในคุณสมบัติที่มีการเก็บรักษาเหมือนที่คุณมี จะทำให้จำนวนการเก็บรักษาเพิ่มขึ้นเป็น 2

ไม่คุณไม่จำเป็นต้องปล่อยมันอีกครั้ง จำนวนการเก็บรักษาสูงสุดคือ 2 ดังนั้น 2 รีลีส

person Manish Burman    schedule 13.08.2011