ใช้การจัดสรร init แทนของใหม่


344

การเรียนรู้ Objective-C และการอ่านโค้ดตัวอย่างฉันสังเกตว่ามักจะสร้างวัตถุโดยใช้วิธีนี้:

SomeObject *myObject = [[SomeObject alloc] init];

แทน:

SomeObject *myObject = [SomeObject new];

มีเหตุผลสำหรับสิ่งนี้เพราะฉันได้อ่านว่าพวกเขาจะเทียบเท่า?


12
ฉันไม่รู้ด้วยซ้ำว่าเป็นไปได้! เนื้อหาทั้งหมดที่ฉันได้อ่านอ้างว่าไม่มีคำหลักใหม่!
Jonathan

78
จริงๆแล้ว "ใหม่" ไม่ใช่คำหลักใน Objective-C แต่ NSObject ใช้วิธีการเรียน "ใหม่" ซึ่งเรียกง่ายๆว่า "alloc" และ "init"
ดอนคอค

3
โจนาธานนั่นคือสิ่งที่กระตุ้นคำถามของฉัน มันอาจจะเทียบเท่ากับการใช้งาน แต่ [[alloc] init] นั้นเป็นสำนวนที่เด่นชัด
willc2

1
ฉันคิดว่า Apple (จากสิ่งที่ฉันจำได้จากการบรรยาย iTunes Stanford ของพวกเขา) เพียงสนับสนุนให้คุณใช้ alloc init แทนเพื่อให้คุณสามารถเข้าใจกระบวนการที่เกิดขึ้น พวกเขายังไม่ได้ใช้โค้ดตัวอย่างจำนวนมากใหม่ดังนั้นการจัดสรร init ดูเหมือนจะเป็นนิสัยที่ดีโดยทั่วไปที่ Apple พยายามส่งเสริม
PostCodeism

คำตอบ:


290

มีเหตุผลมากมายที่นี่: http://macresearch.org/difference-between-alloc-init-and-new

บางคนเลือกคือ:

  • newไม่รองรับ initializers ที่กำหนดเอง (เช่นinitWithString)
  • alloc-init ชัดเจนกว่า new

ความคิดเห็นทั่วไปดูเหมือนว่าคุณควรใช้สิ่งที่คุณพอใจ


8
ถ้าคลาสของคุณใช้ -init เป็น initializer ที่กำหนด + ใหม่จะเรียกมัน สิ่งที่ Jeremy อ้างถึงคือถ้าคุณมี initializer แบบกำหนดเองที่ไม่ใช่ -init -initWithName: ตัวอย่างเช่น
bbum

87
ไม่มีอะไรที่จะหยุดคุณจากการดำเนินการเป็นเช่นกันถ้าคุณดำเนินการแล้ว+newWithString: -initWithStringไม่ว่ากันทั่วไปว่า โดยส่วนตัวฉันมักจะใช้newเมื่อเครื่องมือกำหนดค่าเริ่มต้นเป็นinitเพียงแค่สั้นและหวาน
PeyloW

11
ฉันรู้ว่านี้เป็นหัวข้อเก่า แต่ผมแค่อยากจะความเครียดที่คุณไม่ควร+newWithString:ดำเนินการ นั่นเป็นการแยกความกังวลออกจากกัน เพราะเมื่อคุณเพียงต้องการที่จะใช้-initแล้วมีเหตุผลที่จะไม่ใช้เพียง+newแต่
โจนาธานสเตอร์ลิง

7
@JonathanSterling: Apple มีหลายครั้งที่ดูเหมือนว่าพวกเขากำลังทำสิ่งที่คุณแนะนำ ตัวอย่าง[[NSString alloc] initWithFormat:...]และ[NSString stringWithFormat:...]มีความเท่าเทียมกัน คุณกำลังบอกว่า Apple ละเมิดการแยกข้อกังวลและไม่ควรใช้วิธีนี้ (หมายเหตุ: ฉันไม่ได้พยายามที่จะวางตัว; ฉันแค่อยากจะได้รับข้อมูลเพิ่มเติมและรู้ว่าต่อไปนี้นำไปสู่แอปเปิ้ลเป็นความคิดที่ไม่ดี)
Senseful

6
@Senseful ฉันเชื่อว่าวันที่กลับไปก่อน ARC (หรือการเก็บขยะ) สองสิ่งนี้เราไม่เทียบเท่ากัน stringWithFormat: จะคืนค่าสตริงอัตโนมัติขณะที่จัดสรร: init: จะต้องถูกปล่อยด้วยตัวเองหรืออัตโนมัติหรือไม่เช่นนั้นจะทำให้หน่วยความจำรั่ว
msfeldstein

139

คำถามเก่ามาก แต่ฉันได้เขียนตัวอย่างเพื่อความสนุกสนานบางทีคุณอาจพบว่ามันมีประโยชน์;)

#import "InitAllocNewTest.h"

@implementation InitAllocNewTest

+(id)alloc{
    NSLog(@"Allocating...");
    return [super alloc];
}

-(id)init{
    NSLog(@"Initializing...");
    return [super init];
}

@end

ในฟังก์ชั่นหลักทั้งสองคำสั่ง:

[[InitAllocNewTest alloc] init];

และ

[InitAllocNewTest new];

ส่งผลให้ผลลัพธ์เดียวกัน:

2013-03-06 16:45:44.125 XMLTest[18370:207] Allocating...
2013-03-06 16:45:44.128 XMLTest[18370:207] Initializing...

5
คำตอบที่ยอดเยี่ยม! เพียงแค่ต้องการเพิ่มว่าการใช้ + ใหม่นั้นยอดเยี่ยมสำหรับกรณีที่คุณต้องการใช้ -init และไม่มีอะไรพิเศษเช่น -initWithSomething: ...
cgossain

น่าเสียดายที่ตัวอย่างนี้ไม่ได้พิสูจน์ว่าพวกเขาเหมือนกัน มันเป็นเพียงตัวอย่างที่พวกเขาให้ผลลัพธ์เดียวกัน
Vince O'Sullivan

10
น่าเสียดายที่ตัวอย่างนี้ไม่ได้พิสูจน์ว่าพวกเขาเหมือนกัน มันเป็นเพียงตัวอย่างที่เกิดขึ้นให้ผลลัพธ์เดียวกัน ในทางตรงกันข้ามสิ่งนี้พิสูจน์ได้ว่าพวกมันแตกต่างกัน ... นำตัวอย่างด้านบนมาปรับเปลี่ยน "InitAllocNewTest.h" ดังนี้: @interface InitAllocNewTest: NSObject - (instancetype) __unavailable init; @end [[InitAllocNewTest alloc] init]จะไม่รวบรวมในขณะที่[InitAllocNewTest new]ไม่ได้รับผลกระทบ (ขอโทษสำหรับการขาดตัวแบ่งบรรทัด ฯลฯ )
Vince O'Sullivan

1
@ VinceO'Sullivan จุดดี ซึ่งหมายความว่าหากต้องการให้ init ไม่พร้อมใช้งานเช่นเดียวกับในชั้นเรียนเดี่ยว ๆ ควรปิดใช้งานใหม่เช่นกัน ฉันจะไม่แตะที่นี่ว่าซิงเกิลดีหรือไม่ดี
3099609

ฉันมีคำถามจากรหัสข้างต้น ทำไม "return [super init];" โดยทั่วไป init เป็นวิธีการที่สมาชิกของคลาสถูกเตรียมใช้งานเหตุใดการเปลี่ยนแปลงของตัวชี้จึงแปลกมาก!
Pruthvidhar Rao Nadunooru

52

+newเทียบเท่ากับการนำไปใช้+alloc/-initของ Apple NSObjectมันไม่น่าเป็นไปได้สูงที่สิ่งนี้จะเปลี่ยนแปลง แต่ขึ้นอยู่กับระดับความหวาดระแวงของคุณเอกสารของ Apple สำหรับ+newปรากฏขึ้นเพื่อให้สามารถเปลี่ยนการใช้งาน (และทำลายความเท่าเทียมกัน) ในอนาคต ด้วยเหตุนี้เพราะ "อย่างชัดเจนจะดีกว่านัย" และเพื่อความต่อเนื่องทางประวัติศาสตร์ชุมชน Objective-C +newโดยทั่วไปหลีกเลี่ยง อย่างไรก็ตามคุณสามารถมักจะจุด comers Java ที่ผ่านมาเพื่อวัตถุประสงค์-C +newโดยใช้พากเพียรของพวกเขา


8
แม้ว่าจะเป็นเรื่องจริงบ่อยครั้ง แต่ก็มีค่ายที่ให้ความสำคัญกับความตึงเครียดเช่นกันซึ่งในกรณีนี้จะมีความชัดเจนมากขึ้นเมื่อมีข้อกังวลที่ชัดเจนและเป็นปัจจุบันที่รับประกัน
Peter DeWeese

27
ฉัน downvote นี้เพราะ+newมีมาตั้งแต่ NeXT วัน หากมีสิ่งใด+newเป็นเครื่องหมายของคนที่เรียนรู้ objc มานานแล้ว ฉันเห็นผู้คนจำนวนมากที่เพิ่งเริ่มใช้ภาษาใหม่หรือผู้ที่เคยเขียนมันมานานหลายปี แต่ชัดเจนหลังจากยุคเฟื่องฟูของ iOS ไม่มีความ+newหมายว่าอะไร อย่างที่สอง+newก็คือเก่ามากและจากวัน NeXT, Apple จะค่อนข้างบ้าที่จะเปลี่ยนมันในทางที่ทำลายรหัสเก่าโดยเฉพาะอย่างยิ่งเมื่อพิจารณาจากฐานรหัสของตัวเองอาจจะทิ้งกระจุยกระจายไป
asveikau

1
ฉันค่อนข้างมั่นใจว่าnewสำนวนนี้มาจาก Smalltalk มันยังใช้ใน Ruby และทั้ง Objective-C และ Ruby นั้นมีไวยากรณ์และแบบแผนมากมายจาก Smalltalk
Brendon Roberto

3
อนุญาตเฉพาะการเปลี่ยนแปลงในการจัดสรร เอกสาร -init ของรัฐจะถูกเรียกอย่างชัดเจน ดังนั้นจึงขึ้นอยู่กับว่าคุณจะยกเลิกการจัดสรรมากน้อยเพียงใด
Kendall Helmstetter Gelner

7
ฉันไม่สามารถจินตนาการได้ว่าทำไมการแก้ปัญหาที่คุณต้องพิมพ์มากกว่าจะเป็นที่ต้องการ (alloc init) โดยเฉพาะอย่างยิ่งในภาษา verbose เช่น Objective-C ซึ่งการกดแป้นบันทึกจะช่วยประหยัดเวลาของคุณ "นักพัฒนา Java ที่ชอกช้ำ" เพียงแค่ใช้ทักษะการวิเคราะห์เพื่อใช้เวลาในการเขียนโค้ดน้อยลงแทนที่จะพิมพ์อักขระพิเศษที่ไม่จำเป็นซึ่งให้ผลลัพธ์การทำงานที่เหมือนกัน
DiscDev

9

บ่อยครั้งที่คุณจะต้องผ่านข้อโต้แย้งinitและอื่น ๆ [[SomeObject alloc] initWithString: @"Foo"]ที่คุณจะใช้วิธีการที่แตกต่างกันเช่น หากคุณกำลังใช้ในการเขียนนี้คุณจะได้รับในนิสัยของการทำวิธีนี้และอื่น ๆอาจจะมาขึ้นตามธรรมชาติที่[[SomeObject alloc] init][SomeObject new]


7

หนึ่งคำตอบสั้น ๆ คือ:

  1. ทั้งสองเหมือนกัน แต่
  2. 'ใหม่' ใช้งานได้เฉพาะกับ initializer พื้นฐาน 'พื้นฐาน' เท่านั้นและจะไม่ทำงานกับ initializers อื่น ๆ (เช่น initWithString :)

3

สำหรับบันทึกย่อด้านข้างฉันใช้เป็นการส่วนตัว[Foo new]หากฉันต้องการให้บางสิ่งบางอย่างใน init ทำโดยไม่ใช้ค่าส่งคืนทุกที่ หากคุณไม่ได้ใช้การส่งคืนของ[[Foo alloc] init]ที่ใดก็ตามคุณจะได้รับคำเตือน มากหรือน้อยฉันใช้[Foo new]ทำอาหารตา


3

ฉันมาสายนี้มาก แต่ฉันต้องการพูดถึงว่าใหม่ไม่ปลอดภัยใน Obj-C กับโลก Swift Swift จะสร้างวิธีการเริ่มต้นเท่านั้นหากคุณไม่ได้สร้างเครื่องมือเริ่มต้นอื่น ๆ การเรียกสิ่งใหม่ในคลาสที่รวดเร็วด้วย initializer แบบกำหนดเองจะทำให้เกิดความผิดพลาด ถ้าคุณใช้ alloc / init คอมไพเลอร์จะบ่นว่าไม่มีอยู่


1

หากใหม่ทำงานให้คุณแล้วมันจะทำให้โค้ดของคุณเล็กลงเช่นกัน หากคุณจะโทร[[SomeClass alloc] init]ในหลาย ๆ ที่ในรหัสของคุณคุณจะสร้าง Hot Spot ในการนำไปใช้งานใหม่นั่นคือใน objc runtime ซึ่งจะช่วยลดจำนวนแคชที่คุณพลาดไป

ในความเข้าใจของฉันหากคุณจำเป็นต้องใช้ initializer แบบกำหนดเอง [[SomeClass alloc] initCustom]ในความเข้าใจของผมถ้าคุณจำเป็นต้องใช้ที่กำหนดเองการเริ่มต้นใช้งาน

[SomeClass new]หากคุณไม่ได้ใช้


1
ฉันจะโต้แย้งด้วย "ถ้าคุณต้องการใช้ initializer แบบกำหนดเองใช้ [[SomeClass alloc] initCustom]" หากคุณต้องการเครื่องมือกำหนดค่าเริ่มต้นที่กำหนดเองโดยไม่มีพารามิเตอร์ใด ๆ อย่าทำสิ่งที่คุณแนะนำเลยเพียงแค่แทนที่initฟังก์ชั่นเริ่มต้นและใช้งาน[[SomeClass alloc] init];หากคุณต้องการพารามิเตอร์ แต่ก็ไม่เคยทำสิ่งนั้น[[SomeClass alloc] initWith:...];เลย สุดท้ายถ้าคุณแทนที่initฟังก์ชั่นด้วยการใช้งานที่กำหนดเองคุณสามารถโทรหาnewเมื่อสร้างวัตถุและมันจะยังคงเรียกการinitใช้งานที่กำหนดเอง
dirtydanee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.