อะไรคือแนวปฏิบัติที่ดีที่สุดที่คุณใช้เมื่อเขียน Objective-C และ Cocoa [ปิด]


346

ฉันรู้เกี่ยวกับHIG (ซึ่งค่อนข้างมีประโยชน์!) แต่คุณใช้วิธีการเขียนโปรแกรมแบบใดเมื่อเขียน Objective-C และเฉพาะเจาะจงมากขึ้นเมื่อใช้ Cocoa (หรือ CocoaTouch)


ดูโพสต์บล็อกนี้ดีมาก ironwolf.dangerousgames.com/blog/archives/913
user392412

คำตอบ:


398

มีบางสิ่งที่ฉันเริ่มทำซึ่งฉันไม่คิดว่าเป็นมาตรฐาน:

1) ด้วยการถือกำเนิดของคุณสมบัติฉันไม่ใช้ตัวแปรคลาส "_" เพื่อนำหน้า "ส่วนตัว" อีกต่อไป ท้ายที่สุดถ้าคลาสอื่นสามารถเข้าถึงตัวแปรได้ควรมีคุณสมบัติหรือไม่? ฉันไม่ชอบคำนำหน้า "_" เสมอสำหรับการสร้างโค้ดที่ไม่ดีและตอนนี้ฉันสามารถละไว้ได้

2) เมื่อพูดถึงเรื่องส่วนตัวฉันชอบที่จะกำหนดคำจำกัดความวิธีการส่วนตัวภายในไฟล์. m ในนามสกุลชั้นเรียนโดยทำดังนี้

#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass

ทำไมไฟล์. h ที่ยุ่งเหยิงกับสิ่งที่คนนอกไม่ควรสนใจ? empty () ใช้งานได้สำหรับหมวดหมู่ส่วนตัวในไฟล์. m และออกคำเตือนการรวบรวมหากคุณไม่ได้ใช้วิธีการที่ประกาศไว้

3) ฉันได้ทำการวาง dealloc ที่ด้านบนของไฟล์. m ใต้คำสั่ง @synthesize สิ่งที่คุณไม่ควรจัดสรรให้อยู่ในอันดับต้น ๆ ของสิ่งที่คุณต้องการคิดถึงในชั้นเรียน โดยเฉพาะอย่างยิ่งในสภาพแวดล้อมเช่น iPhone

3.5) ในเซลล์ตารางทำให้ทุกองค์ประกอบ (รวมถึงเซลล์เอง) ทึบแสงเพื่อประสิทธิภาพ นั่นหมายถึงการตั้งค่าสีพื้นหลังที่เหมาะสมในทุกสิ่ง

3.6) เมื่อใช้ NSURLConnection เป็นกฎที่คุณอาจต้องการใช้วิธีมอบสิทธิ์:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
      return nil;
}

ฉันพบว่าการโทรทางเว็บส่วนใหญ่นั้นมีลักษณะเฉพาะตัวและเป็นข้อยกเว้นมากกว่ากฎที่คุณต้องการรับการตอบกลับโดยเฉพาะอย่างยิ่งการโทรผ่านเว็บ การใช้วิธีการตามที่แสดงปิดการแคชการตอบสนอง

ที่น่าสนใจคือเคล็ดลับเฉพาะของ iPhone ที่ดีจาก Joseph Mattiello (ได้รับในรายชื่อผู้รับจดหมายของ iPhone) มีมากกว่านี้ แต่สิ่งเหล่านี้มีประโยชน์มากที่สุดที่ฉันคิด (โปรดสังเกตว่าตอนนี้มีการแก้ไขเล็กน้อยจากต้นฉบับเล็กน้อยเพื่อรวมรายละเอียดที่มีให้ในการตอบกลับ)

4) ใช้ความแม่นยำสองเท่าหากจำเป็นเช่นเมื่อทำงานกับ CoreLocation ให้แน่ใจว่าคุณจบค่าคงที่ของคุณใน 'f' เพื่อให้ gcc เก็บไว้เป็นลอย

float val = someFloat * 2.2f;

นี่เป็นสิ่งสำคัญส่วนใหญ่เมื่อsomeFloatจริง ๆ แล้วอาจเป็นสองเท่าคุณไม่จำเป็นต้องใช้คณิตศาสตร์แบบผสมเนื่องจากคุณสูญเสียความแม่นยำใน 'val' บนที่เก็บข้อมูล แม้ว่าจำนวนจุดลอยตัวจะได้รับการสนับสนุนในฮาร์ดแวร์บน iPhone แต่อาจต้องใช้เวลามากขึ้นในการคำนวณเลขคณิตสองเท่าเมื่อเทียบกับความแม่นยำเดี่ยว อ้างอิง:

ในโทรศัพท์รุ่นเก่าที่คาดคะเนการคำนวณจะทำงานด้วยความเร็วเดียวกัน แต่คุณสามารถมีส่วนประกอบที่มีความแม่นยำมากขึ้นในการลงทะเบียนมากกว่าสองเท่าดังนั้นสำหรับการคำนวณจำนวนมากความแม่นยำเดี่ยวจะจบลงด้วยการได้เร็วขึ้น

5) nonatomicการตั้งค่าคุณสมบัติของคุณเป็น พวกเขากำลังatomicตามค่าเริ่มต้นและเมื่อการสังเคราะห์รหัสสัญญาณจะถูกสร้างขึ้นเพื่อป้องกันปัญหาหลายเธรด 99% ของคุณอาจไม่จำเป็นต้องกังวลเกี่ยวกับเรื่องนี้และรหัสจะบวมน้อยลงและมีประสิทธิภาพหน่วยความจำมากขึ้นเมื่อตั้งค่าเป็น nonatomic

6) SQLite อาจเป็นวิธีที่รวดเร็วและรวดเร็วในการแคชชุดข้อมูลขนาดใหญ่ แอปพลิเคชันแผนที่สำหรับอินสแตนซ์สามารถแคชไทล์ของมันลงในไฟล์ SQLite ส่วนที่แพงที่สุดคือดิสก์ I / O หลีกเลี่ยงการเขียนขนาดเล็กจำนวนมากโดยการส่งBEGIN;และCOMMIT;ระหว่างบล็อกขนาดใหญ่ เราใช้ตัวจับเวลา 2 วินาทีสำหรับอินสแตนซ์ที่ตั้งค่าใหม่ในการส่งใหม่แต่ละครั้ง เมื่อมันหมดเราจะส่ง COMMIT ซึ่งทำให้งานเขียนทั้งหมดของคุณมีขนาดใหญ่ SQLite เก็บข้อมูลการทำธุรกรรมลงในดิสก์และการทำเช่นนี้การเริ่มต้น / สิ้นสุดการตัดเพื่อหลีกเลี่ยงการสร้างไฟล์ธุรกรรมจำนวนมากรวมกลุ่มการทำธุรกรรมทั้งหมดไว้ในไฟล์เดียว

นอกจากนี้ SQL จะบล็อก GUI ของคุณถ้ามันอยู่ในเธรดหลักของคุณ หากคุณมีคิวรีที่ยาวมากคุณควรเก็บคิวรีของคุณเป็นวัตถุคงที่และเรียกใช้ SQL ของคุณบนเธรดแยกต่างหาก ตรวจสอบให้แน่ใจว่าได้ตัดสิ่งที่แก้ไขฐานข้อมูลสำหรับสตริงการสืบค้นใน@synchronize() {}บล็อก สำหรับข้อความค้นหาสั้น ๆ ให้ทิ้งสิ่งต่าง ๆ ไว้บนเธรดหลักเพื่อความสะดวกที่ง่ายขึ้น

เคล็ดลับการเพิ่มประสิทธิภาพ SQLite เพิ่มเติมอยู่ที่นี่ถึงแม้ว่าเอกสารจะล้าสมัยหลายประเด็นอาจยังดี

http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html


3
เคล็ดลับดีเกี่ยวกับเลขคณิตสองครั้ง
Adam Ernst

8
ขณะนี้ส่วนขยายของชั้นเรียนเป็นวิธีที่ต้องการสำหรับวิธีการส่วนตัว: developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/…
Casebash

9
คำแนะนำของคุณเกี่ยวกับการเพิ่มทวีคูณบน iPhone นั้นล้าสมัยstackoverflow.com/questions/1622729/…
Casebash

3
ไม่ล้าสมัย; ผิดทั้งหมด: iPhone ดั้งเดิมรองรับลอยและสองเท่าในฮาร์ดแวร์ที่ความเร็วประมาณเดียวกัน SQLite ไม่เก็บธุรกรรมในหน่วยความจำ พวกเขาถูกเจอร์นัลบนดิสก์ การสืบค้นที่มีความยาวเพียงบล็อก UI ของคุณ มันยุ่งน้อยกว่าในการรันทุกอย่างในเธรดหลักและใช้การสืบค้นที่เร็วขึ้น
tc

1
@tc: ฉันแก้ไขรายการ SQL เกี่ยวกับธุรกรรมโปรดทราบว่าฉันเองไม่ได้เขียนรายการสี่รายการหรือมากกว่านั้น ฉันยังชี้แจงส่วนเกี่ยวกับการย้ายข้อความค้นหาไปยังพื้นหลังนั้นเป็นข้อความค้นหาที่ยาวมากเท่านั้น (บางครั้งคุณก็ไม่สามารถทำให้ข้อความสั้นลง) แต่การที่จะเรียกสิ่งทั้งหมดว่า "ผิด" เพราะมีเพียงไม่กี่จุดฉันรู้สึกค่อนข้างรุนแรง นอกจากนี้คำตอบข้างต้นระบุไว้แล้ว: "ในโทรศัพท์รุ่นเก่าที่คาดคะเนการคำนวณจะทำงานด้วยความเร็วเท่ากัน" แต่ให้สังเกตส่วนที่เกี่ยวกับการลงทะเบียนความแม่นยำเดี่ยวจำนวนมากซึ่งทำให้พวกเขายังคงใช้งานได้ดีกว่า
Kendall Helmstetter Gelner

109

อย่าใช้สตริงที่ไม่รู้จักเป็นสตริงรูปแบบ

เมื่อเมธอดหรือฟังก์ชั่นรับอาร์กิวเมนต์สตริงรูปแบบคุณควรตรวจสอบให้แน่ใจว่าคุณสามารถควบคุมเนื้อหาของสตริงรูปแบบได้

ตัวอย่างเช่นเมื่อบันทึกสตริงการดึงดูดให้ส่งผ่านตัวแปรสตริงเป็นอาร์กิวเมนต์เพียงอย่างเดียวNSLogคือ:

    NSString *aString = // get a string from somewhere;
    NSLog(aString);

ปัญหานี้คือว่าสตริงอาจมีตัวละครที่ถูกตีความว่าเป็นสตริงรูปแบบ สิ่งนี้สามารถนำไปสู่ผลลัพธ์ที่ผิดพลาดขัดข้องและปัญหาด้านความปลอดภัย คุณควรแทนที่ตัวแปรสตริงเป็นสตริงรูปแบบแทน

    NSLog(@"%@", aString);

4
ฉันเคยถูกคนนี้กัดมาก่อน
Adam Ernst

นี่เป็นคำแนะนำที่ดีสำหรับภาษาการเขียนโปรแกรมใด ๆ
Tom Fobear

107

ใช้การตั้งชื่อโกโก้มาตรฐานและการจัดรูปแบบอนุสัญญาและคำศัพท์แทนสิ่งที่คุณคุ้นเคยจากสภาพแวดล้อมอื่น มีนักพัฒนาโกโก้อยู่มากมายและเมื่ออีกคนหนึ่งเริ่มทำงานกับโค้ดของคุณมันจะเข้าถึงได้ง่ายกว่าถ้ามันดูและรู้สึกคล้ายกับโค้ดโกโก้อื่น ๆ

ตัวอย่างของสิ่งที่ต้องทำและสิ่งที่ไม่ควรทำ:

  • ไม่ได้ประกาศid m_something;ในอินเตอร์เฟซของวัตถุและเรียกมันว่าตัวแปรสมาชิกหรือข้อมูล ; ใช้somethingหรือ_somethingสำหรับชื่อและเรียกมันว่าตัวแปรเช่น
  • อย่าชื่อทะเยอทะยาน-getSomething; -somethingชื่อโกโก้ที่เหมาะสมเป็นเพียง
  • อย่าตั้งชื่อหมา-something:; มันควรจะเป็น-setSomething:
  • ชื่อวิธีจะสลับกับการขัดแย้งและรวมถึง colons; มันไม่ได้-[NSObject performSelector:withObject:]NSObject::performSelector
  • ใช้ตัวคั่นระหว่างกัน (CamelCase) ในชื่อเมธอดพารามิเตอร์ตัวแปรชื่อคลาส ฯลฯ แทนที่จะเป็นแถบล่าง (ขีดล่าง)
  • ชื่อคลาสเริ่มต้นด้วยตัวอักษรตัวพิมพ์ใหญ่ตัวแปรและชื่อเมธอดด้วยตัวพิมพ์เล็ก

ไม่ว่าคุณจะทำอะไรอย่าใช้ Win16 / Win32-style สัญกรณ์ฮังการี แม้แต่ไมโครซอฟท์ก็ยอมแพ้ในเรื่องนี้ด้วยการย้ายไปยังแพลตฟอร์ม. NET


5
ฉันจะเถียงอย่าใช้ setSomething: / อย่างใดอย่างหนึ่ง - แทนที่จะใช้คุณสมบัติ ณ จุดนี้มีคนไม่กี่คนที่ต้องการกำหนดเป้าหมายไปที่ Tiger (เหตุผลเดียวที่จะไม่ใช้คุณสมบัติ)
Kendall Helmstetter Gelner

18
คุณสมบัติยังคงสร้างเมธอด accessor สำหรับคุณและแอ็ตทริบิวต์ getter = / setter = บนคุณสมบัติให้คุณระบุชื่อของเมธอด นอกจากนี้คุณสามารถใช้ [foo something] ไวยากรณ์แทน foo.something ไวยากรณ์ที่มีคุณสมบัติ ดังนั้นการตั้งชื่อ accessor ยังคงเกี่ยวข้อง
Chris Hanson

3
นี่เป็นข้อมูลอ้างอิงที่ยอดเยี่ยมสำหรับบางคนที่มาจากภาษา C ++ ซึ่งฉันได้ทำสิ่งที่คุณแนะนำเป็นส่วนใหญ่
Clinton Blackmore

4
ตัวตั้งค่าไม่ควรทำให้บางสิ่งบางอย่างถูกบันทึกลงในฐานข้อมูล มีเหตุผลหลักที่ข้อมูลหลักมีวิธีการบันทึก: ใน NSManagedObjectContext แทนที่จะให้ตัวตั้งค่าสร้างการอัพเดตทันที
395 Chris

2
ฉันสงสัยว่ามันไม่ใช่ตัวเลือก แต่อาจต้องมีการทบทวนสถาปัตยกรรมแอปของคุณอีกครั้ง (เพื่อความชัดเจน: ฉันไม่ได้พูดว่า "คุณควรใช้ Core Data" ฉันกำลังพูดว่า "Setters ไม่ควรบันทึกลงในฐานข้อมูล") มีบริบทในการจัดการกราฟวัตถุแทนที่จะบันทึกแต่ละวัตถุในนั้น เป็นไปได้จริงและเป็นทางออกที่ดีกว่า
Chris Hanson

106

IBOutlets

ในอดีตการจัดการหน่วยความจำของร้านไม่ดี แนวปฏิบัติที่ดีที่สุดในปัจจุบันคือการประกาศร้านค้าเป็นคุณสมบัติ:

@interface MyClass :NSObject {
    NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end

การใช้คุณสมบัติทำให้ซีแมนทิกส์การจัดการหน่วยความจำชัดเจน มันยังให้รูปแบบที่สอดคล้องกันถ้าคุณใช้การสังเคราะห์ตัวแปรอินสแตนซ์


1
จะไม่โหลดของปลายปากกาเก็บไว้สองครั้งหรือไม่ (หนึ่งครั้งในปลายปากกาวินาทีโดยกำหนดให้กับคุณสมบัติ) ฉันควรจะปล่อยผู้ที่อยู่ใน dealloc หรือไม่?
Kornel

6
คุณต้องไม่มีศูนย์ใน viewDidUnload (iPhone OS 3.0+) หรือใน setView แบบกำหนดเอง: เพื่อหลีกเลี่ยงการรั่วไหล เห็นได้ชัดว่าคุณควรปล่อยใน dealloc เช่นกัน
Frank Szczerba

2
โปรดจำไว้ว่าไม่ใช่ทุกคนที่เห็นด้วยกับรูปแบบนี้: weblog.bignerdranch.com/?p=95
Michael

นี่คือสิ่งที่ Apple ทำเช่นกัน "การเริ่มต้นพัฒนา iPhone 3" กล่าวถึงการเปลี่ยนแปลงนี้จากเวอร์ชั่นก่อนหน้าด้วย
ustun

ฉันพูดถึงเรื่องนี้ในความคิดเห็นอื่น แต่ควรวางไว้ที่นี่: เมื่อการสังเคราะห์ ivar แบบไดนามิกเริ่มเกิดขึ้นสำหรับแอป iOS (ถ้า / เมื่อใด) คุณจะดีใจที่คุณวาง IBOutlet ไว้ในทรัพย์สินเทียบกับ ivar!
Joe D'Andrea

97

ใช้ LLVM / Clang Static Analyzer

หมายเหตุ: ภายใต้ Xcode 4 ตอนนี้ถูกสร้างขึ้นใน IDE

คุณใช้Clang Static Analyzerเพื่อ - ไม่น่าแปลกใจ - วิเคราะห์ C และรหัส Objective-C ของคุณ (ยังไม่มี C ++) บน Mac OS X 10.5 มันง่ายที่จะติดตั้งและใช้งาน:

  1. ดาวน์โหลดเวอร์ชั่นล่าสุดจากหน้านี้
  2. จากบรรทัดคำสั่งcdไปยังไดเรกทอรีโครงการของคุณ
  3. scan-build -k -V xcodebuildปฏิบัติ

(มีข้อ จำกัด เพิ่มเติมบางอย่าง ฯลฯ โดยเฉพาะอย่างยิ่งคุณควรวิเคราะห์โครงการในการกำหนดค่า "Debug" - ดูที่http://clang.llvm.org/StaticAnalysisUsage.html http://clang.llvm.org/StaticAnalysisUsage.htmlเพื่อดูรายละเอียด - แต่ก็มากหรือน้อย สิ่งที่เดือดลงไป)

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


1
ฉันมีปัญหาในการทำให้สิ่งนี้ทำงานจนกว่าฉันจะทำตามคำแนะนำเหล่านี้: oiledmachine.com/posts/2009/01/06/…
bbrown

15
ใน XCode 3.2.1 บน Snow Leopard มันมีอยู่แล้วภายในคุณสามารถรันด้วยตนเองโดยใช้Run -> Build และ Analyzeหรือคุณสามารถเปิดใช้มันสำหรับ build ทั้งหมดผ่านการตั้งค่า build "Run Static Analyzer" โปรดทราบว่าในปัจจุบันเครื่องมือนี้รองรับเฉพาะ C และ Objective-C แต่ไม่ใช่ C ++ / Objective-C ++
oefe

94

อันนี้บอบบาง แต่มีประโยชน์ deallocหากคุณผ่านตัวเองเป็นผู้แทนไปยังวัตถุอื่นรีเซ็ตผู้รับมอบสิทธิ์ของวัตถุว่าก่อนที่คุณ

- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}

ด้วยการทำเช่นนี้คุณจะมั่นใจได้ว่าจะไม่มีการส่งวิธีการมอบสิทธิ์อีกต่อไป ในขณะที่คุณกำลังจะไปdeallocและหายไปในอีเธอร์คุณต้องการแน่ใจว่าไม่มีอะไรสามารถส่งข้อความถึงคุณได้อีกโดยไม่ได้ตั้งใจ โปรดจำไว้ว่า self.someObject อาจถูกเก็บรักษาโดยวัตถุอื่น (อาจเป็นซิงเกิลตันหรือบนสระว่ายน้ำอัตโนมัติหรืออะไรก็ตาม) และจนกว่าคุณจะบอกว่า "หยุดส่งข้อความถึงฉัน!" มันคิดว่าวัตถุที่คุณเพิ่งจะได้รับการจัดสรรคืน เป็นเกมที่ยุติธรรม

การเข้าสู่นิสัยนี้จะช่วยให้คุณรอดพ้นจากความผิดพลาดแปลก ๆ มากมายซึ่งเป็นความเจ็บปวดในการแก้ปัญหา

หลักการเดียวกันนี้ใช้กับการสังเกตการณ์ค่าคีย์และการแจ้งเตือนของ NSN ด้วยเช่นกัน

แก้ไข:

การป้องกันที่ดียิ่งขึ้นการเปลี่ยนแปลง:

self.someObject.delegate = NULL;

เป็น:

if (self.someObject.delegate == self)
    self.someObject.delegate = NULL;

8
ไม่มีอะไรละเอียดเกี่ยวกับเรื่องนี้เอกสารระบุอย่างชัดเจนว่าคุณต้องทำเช่นนี้ จากMemory Management Programming Guide for Cocoa: Additional cases of weak references in Cocoa include, but are not restricted to, table data sources, outline view items, notification observers, and miscellaneous targets and delegates. In most cases, the weak-referenced object is aware of the other object’s weak reference to it, as is the case for circular references, and is responsible for notifying the other object when it deallocates.
johne

มันจะดีกว่าที่จะใช้ศูนย์แทน NULL เพราะ NULL จะไม่เพิ่มหน่วยความจำ
Naveen Shan

nil == NULL@NaveenShan พวกเขาจะตรงเดียวกันยกเว้นว่าnilเป็นidและเป็นNULL void *ใบแจ้งยอดของคุณไม่เป็นความจริง

@WTP yep, nil == NULL แต่การใช้ nil นั้นเป็นวิธีที่ต้องการอย่างชัดเจนหากคุณดูตัวอย่างรหัสแอปเปิ้ลพวกเขากำลังใช้ nil อยู่ทุกหนทุกแห่งและอย่างที่คุณบอกว่า nil เป็น id ซึ่งทำให้มันเป็นโมฆะ * ในกรณีที่คุณส่งรหัสนั่นคือ
Ahti

1
@Ahti ตรงและNil(ตัวพิมพ์ใหญ่) Class*เป็นประเภท แม้ว่าพวกมันจะเท่ากัน แต่การใช้สิ่งที่ผิดสามารถแนะนำข้อผิดพลาดเล็ก ๆ ที่น่ารังเกียจโดยเฉพาะอย่างยิ่งใน Objective-C ++

86

@kendell

แทน:

@interface MyClass (private)
- (void) someMethod
- (void) someOtherMethod
@end

ใช้:

@interface MyClass ()
- (void) someMethod
- (void) someOtherMethod
@end

ใหม่ใน Objective-C 2.0

นามสกุลของคลาสอธิบายไว้ในการอ้างอิง Objective-C 2.0 ของ Apple

"ส่วนขยายคลาสช่วยให้คุณสามารถประกาศ API ที่จำเป็นเพิ่มเติมสำหรับชั้นเรียนในสถานที่อื่นนอกเหนือจากในบล็อก @interface ระดับต้น"

ดังนั้นพวกเขาจึงเป็นส่วนหนึ่งของชั้นเรียนจริง - และไม่ใช่หมวดหมู่ (ส่วนตัว) นอกเหนือจากชั้นเรียน ความแตกต่างที่ลึกซึ้ง แต่สำคัญ


คุณสามารถทำได้ แต่ฉันต้องการติดป้ายกำกับไว้อย่างชัดเจนว่าเป็นส่วน "ส่วนตัว" (มีเอกสารมากกว่าฟังก์ชั่น) แม้ว่าแน่นอนว่ามันชัดเจนอยู่แล้วมากมายจากมันอยู่ในไฟล์. m ...
Kendall Helmstetter Gelner

2
ยกเว้นว่าจะมีความแตกต่างระหว่างหมวดหมู่ส่วนตัวและส่วนขยายของชั้นเรียน: "ส่วนขยายของชั้นช่วยให้คุณสามารถประกาศ API ที่จำเป็นเพิ่มเติมสำหรับชั้นเรียนในสถานที่อื่นนอกเหนือจากในบล็อก @interface ชั้นประถมศึกษาตามที่แสดงในตัวอย่างต่อไปนี้:" ดูลิงก์ในการแก้ไข
schwa

ฉันยอมรับว่ามีความแตกต่างที่คอมไพเลอร์จะเตือนคุณเมื่อคุณไม่ได้ใช้วิธีการ CE - แต่ฉันไม่พบว่าสิ่งสำคัญมากเมื่อวิธีการทั้งหมดอยู่ในไฟล์เดียวกันและส่วนตัวทั้งหมด ฉันยังคงต้องการความสามารถในการบำรุงรักษาของการทำเครื่องหมายการอ้างอิงบล็อกส่วนตัวไปข้างหน้า
Kendall Helmstetter Gelner

3
ฉันไม่เห็น (ส่วนตัว) ที่จะดูแลรักษาได้ดีไปกว่า () หากคุณเป็นห่วงความคิดเห็นที่ดีอาจช่วยได้ แต่เห็นได้ชัดว่ามีชีวิตอยู่และปล่อยให้ชีวิต YMMV เป็นต้น
schwa

17
มีข้อได้เปรียบที่ค่อนข้างสำคัญในการใช้()แทน(Private)(หรือชื่อหมวดหมู่อื่น ๆ ): คุณสามารถประกาศคุณสมบัติเป็นแบบอ่านเขียนในขณะที่สู่สาธารณะโดยจะเป็นแบบอ่านอย่างเดียวเท่านั้น :)
Pascal

75

หลีกเลี่ยงการลบอัตโนมัติ

เนื่องจากปกติแล้วคุณ (1) จะไม่สามารถควบคุมอายุการใช้งานของวัตถุเหล่านั้นได้โดยตรงวัตถุ autoreleded สามารถคงอยู่เป็นเวลานานและเพิ่มหน่วยความจำแอ็พพลิเคชันของคุณโดยไม่จำเป็น ในขณะที่บนเดสก์ท็อปสิ่งนี้อาจมีผลเพียงเล็กน้อยบนแพลตฟอร์มที่มีข้อ จำกัด มากกว่านี้อาจเป็นปัญหาที่สำคัญ ในทุกแพลตฟอร์มดังนั้นโดยเฉพาะอย่างยิ่งในแพลตฟอร์มที่มีข้อ จำกัด มากขึ้นถือว่าเป็นแนวปฏิบัติที่ดีที่สุดในการหลีกเลี่ยงการใช้วิธีการที่จะนำไปสู่วัตถุที่ถูกลบอัตโนมัติและคุณควรใช้รูปแบบการจัดสรร / เริ่มต้นแทน

ดังนั้นมากกว่า:

aVariable = [AClass convenienceMethod];

หากเป็นไปได้คุณควรใช้:

aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];

เมื่อคุณเขียนวิธีการของคุณเองที่ส่งคืนวัตถุที่สร้างขึ้นใหม่คุณสามารถใช้ประโยชน์จากหลักการตั้งชื่อของ Cocoaเพื่อตั้งค่าสถานะไปยังผู้รับว่าจะต้องได้รับการเผยแพร่โดยการเตรียมชื่อวิธีด้วย "ใหม่"

ดังนั้นแทนที่จะ:

- (MyClass *)convenienceMethod {
    MyClass *instance = [[[self alloc] init] autorelease];
    // configure instance
    return instance;
}

คุณสามารถเขียน:

- (MyClass *)newInstance {
    MyClass *instance = [[self alloc] init];
    // configure instance
    return instance;
}

เนื่องจากชื่อวิธีการขึ้นต้นด้วย "ใหม่" ผู้บริโภคของ API ของคุณรู้ว่าพวกเขารับผิดชอบในการปล่อยวัตถุที่ได้รับ (ดูตัวอย่างเช่นวิธีการของ NSObjectControllernewObject )

(1) คุณสามารถควบคุมได้โดยใช้พูลการ autorelease ในพื้นที่ของคุณเอง สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ให้ดูที่สระว่ายน้ำ Autorelease


6
ฉันพบประโยชน์ของการไม่ใช้การเลิกอัตโนมัติเมื่อเทียบกับค่าใช้จ่าย (เช่นมีหน่วยความจำรั่วมากขึ้น) รหัสในเธรดหลักควรใช้งานได้ค่อนข้างสั้น (หรือมิฉะนั้นคุณจะตรึง UI) และสำหรับรหัสพื้นหลังที่ใช้หน่วยความจำนานมากขึ้นคุณสามารถใส่ส่วนที่เน้นหน่วยความจำในพูล autorelease ภายในเครื่องได้เสมอ
adib

56
ฉันไม่เห็นด้วย. คุณควรใช้วัตถุที่ autorelosed ทุกครั้งที่ทำได้ NSAutoreleasePoolหากพวกเขาเพิ่มรอยความทรงจำโดยมากเกินไปคุณควรใช้อีก แต่หลังจากคุณยืนยันว่านี่เป็นปัญหาจริงๆ การเพิ่มประสิทธิภาพก่อนวัยและทุกอย่าง ...
Sven

3
ฉันใช้เวลาน้อยกว่า 40 วินาที วันที่พิมพ์ [someObject release] และการอ่าน "บรรทัดพิเศษ" เมื่อสร้างวัตถุใหม่ แต่ฉันเคยเขียนถึง 17 ชั่วโมงเพื่อค้นหาข้อผิดพลาดอัตโนมัติที่จะปรากฏในกรณีพิเศษเท่านั้นและไม่มีข้อผิดพลาดที่สอดคล้องกันในคอนโซล ดังนั้นฉันจึงเห็นด้วยกับ adib เมื่อเขาทำให้มันเหมือน "ฉันพบประโยชน์ของการไม่ใช้ autorelease เมื่อเทียบกับค่าใช้จ่ายของมัน"
RickiG

7
ฉันเห็นด้วยกับสเวน เป้าหมายหลักควรมีความชัดเจนของรหัสและลดข้อผิดพลาดในการเขียนโค้ดด้วยการเพิ่มประสิทธิภาพหน่วยความจำเฉพาะเมื่อจำเป็น การพิมพ์ [[Foo alloc] init] autorelease] นั้นรวดเร็วและคุณจะจัดการกับปัญหาในการปล่อยวัตถุใหม่นี้ทันที เมื่ออ่านรหัสคุณไม่จำเป็นต้องตามหารุ่นที่เกี่ยวข้องเพื่อให้แน่ใจว่าไม่มีการรั่วไหล
Mike Weller

3
วงจรชีวิตของวัตถุออโต้เซลโลดีถูกกำหนดไว้อย่างดีและสามารถกำหนดได้ในระดับที่เพียงพอ
Eonil

69

บางส่วนได้ถูกกล่าวถึงไปแล้ว แต่นี่คือสิ่งที่ฉันสามารถนึกได้จากส่วนบนของหัว:

  • ปฏิบัติตามกฎการตั้งชื่อของ KVO แม้ว่าคุณจะไม่ได้ใช้ KVO ตอนนี้จากประสบการณ์ของฉันบ่อยครั้งมันก็ยังคงมีประโยชน์ในอนาคต และถ้าคุณใช้ KVO หรือการผูกคุณจำเป็นต้องรู้ว่าสิ่งต่าง ๆ กำลังทำงานอย่างที่ควรจะเป็น สิ่งนี้ไม่เพียง แต่ครอบคลุมถึงวิธีการเข้าถึงและตัวแปรอินสแตนซ์เท่านั้น แต่ยังรวมถึงความสัมพันธ์หลายอย่างการตรวจสอบความถูกต้องการแจ้งเตือนคีย์ที่ขึ้นต่อกันโดยอัตโนมัติและอื่น ๆ
  • ใส่วิธีการส่วนตัวในหมวดหมู่ ไม่เพียงแค่ส่วนต่อประสาน แต่รวมถึงการติดตั้งด้วย มันเป็นการดีที่จะมีระยะห่างแนวความคิดระหว่างวิธีการส่วนตัวและไม่ใช่เอกชน ฉันรวมทุกอย่างไว้ในไฟล์. m ของฉัน
  • ใส่วิธีการเธรดพื้นหลังในหมวดหมู่ เช่นเดียวกับข้างต้น ฉันพบว่ามันเป็นเรื่องดีที่จะรักษาแนวความคิดที่ชัดเจนเมื่อคุณกำลังคิดเกี่ยวกับสิ่งที่อยู่ในเธรดหลักและสิ่งที่ไม่
  • #pragma mark [section]ใช้ โดยปกติฉันจะจัดกลุ่มตามวิธีการของฉันเองการแทนที่แต่ละคลาสย่อยและข้อมูลหรือโปรโตคอลที่เป็นทางการ มันทำให้ง่ายขึ้นมากที่จะข้ามไปยังสิ่งที่ฉันกำลังมองหา ในหัวข้อเดียวกันให้จัดกลุ่มวิธีการที่คล้ายกัน (เช่นวิธีการมอบหมายของมุมมองตาราง) เข้าด้วยกันไม่เพียง แต่ติดไว้ที่ใดก็ได้
  • คำนำหน้าวิธีส่วนตัว & ivars ด้วย _ ฉันชอบรูปลักษณ์และฉันมีโอกาสน้อยที่จะใช้ ivar เมื่อฉันหมายถึงอสังหาริมทรัพย์โดยไม่ตั้งใจ
  • อย่าใช้เมธอด / คุณสมบัติ mutator ใน init & dealloc ฉันไม่เคยมีอะไรเลวร้ายเกิดขึ้นเพราะมัน แต่ฉันสามารถดูตรรกะได้หากคุณเปลี่ยนวิธีการทำสิ่งที่ขึ้นอยู่กับสถานะของวัตถุของคุณ
  • ใส่ IBOutlets ในคุณสมบัติ ที่จริงฉันเพิ่งอ่านอันนี้ที่นี่ แต่ฉันจะเริ่มทำมัน ไม่ว่าหน่วยความจำจะได้ประโยชน์อะไรดูเหมือนว่าจะดีกว่าโวหาร (อย่างน้อยสำหรับฉัน)
  • หลีกเลี่ยงการเขียนโค้ดที่คุณไม่ต้องการจริงๆ สิ่งนี้ครอบคลุมหลายสิ่งหลายอย่างเช่นการทำ ivars เมื่อ#defineทำตามใจชอบหรือแคชอาร์เรย์แทนที่จะเรียงลำดับทุกครั้งที่ต้องการข้อมูล มีหลายสิ่งที่ฉันสามารถพูดเกี่ยวกับเรื่องนี้ได้ แต่บรรทัดล่างจะไม่เขียนโค้ดจนกว่าคุณจะต้องการมันหรือผู้สร้างโปรไฟล์บอกคุณ มันทำให้การบำรุงรักษาง่ายขึ้นในระยะยาว
  • เสร็จสิ้นสิ่งที่คุณเริ่ม การมีรหัสจำนวนมากเสร็จสิ้นแล้วบั๊กกี้เป็นวิธีที่เร็วที่สุดในการฆ่าโปรเจ็กต์ที่ตายแล้ว หากคุณต้องการวิธีการสตับที่ไม่เป็นไรเพียงแค่ระบุโดยการใส่NSLog( @"stub" )ข้างในหรือคุณต้องการติดตามสิ่งต่างๆ

3
ฉันขอแนะนำให้คุณใส่วิธีส่วนตัวในการเรียนต่อเนื่อง (เช่น @interface MyClass () ... @end in .m ของคุณ)
Jason Medeiros

3
แทนที่จะเป็น #PRAGMA คุณสามารถใช้ความคิดเห็น // Mark: [Section] ซึ่งพกพาสะดวกกว่า
aleemb

ยกเว้นว่ามีไวยากรณ์พิเศษที่ฉันขาดหายไป // Mark: ไม่ได้เพิ่มป้ายกำกับในเมนูแบบเลื่อนลงฟังก์ชั่นของ Xcode ซึ่งเป็นครึ่งหนึ่งของเหตุผลในการใช้งาน
Marc Charbonneau

6
คุณต้องใช้ตัวพิมพ์ใหญ่ "// MARK: ... " เพื่อให้มันปรากฏขึ้นในรายการแบบหล่นลง
Rhult

3
ในส่วนที่เกี่ยวกับFinish what you startคุณยังสามารถใช้// TODO:เพื่อทำเครื่องหมายรหัสให้เสร็จซึ่งจะปรากฏในรายการแบบหล่นลง
iwasrobbed

56

เขียนการทดสอบหน่วย คุณสามารถทดสอบจำนวนมากของสิ่งที่อยู่ในโกโก้ที่อาจจะยากในกรอบอื่น ๆ ตัวอย่างเช่นด้วยรหัส UI คุณสามารถยืนยันได้ว่ามีการเชื่อมต่อสิ่งต่าง ๆ ตามที่ควรเชื่อใจได้ว่าจะทำงานเมื่อมีการใช้งาน และคุณสามารถตั้งค่าสถานะ & เรียกใช้เมธอดตัวแทนได้อย่างง่ายดายเพื่อทดสอบ

นอกจากนี้คุณยังไม่มีการมองเห็นแบบสาธารณะและแบบที่ได้รับการป้องกันเทียบกับวิธีส่วนตัวที่จะได้รับในการเขียนแบบทดสอบสำหรับภายใน


คุณแนะนำกรอบการทดสอบอะไรบ้าง
melfar

13
Xcode รวมถึง OCUnit, กรอบการทดสอบหน่วย Objective-C และการสนับสนุนสำหรับการรวมกลุ่มของการทดสอบหน่วยเป็นส่วนหนึ่งของกระบวนการสร้างของคุณ
344 Chris

55

กฎทอง: ถ้าคุณallocแล้วคุณrelease!

อัปเดต: ยกเว้นว่าคุณกำลังใช้งาน ARC อยู่


26
นอกจากนี้ถ้าคุณcopy, mutableCopy, หรือnew retain
สเวน

54

อย่าเขียน Objective-C ราวกับว่าเป็น Java / C # / C ++ / etc

ฉันเคยเห็นทีมที่เคยเขียนโปรแกรมเว็บ Java EE ลองเขียนแอปพลิเคชัน Cocoa บนเดสก์ท็อป ราวกับว่ามันเป็นเว็บแอปพลิเคชัน Java EE มี AbstractFooFactory และ FooFactory มากมายและ IFoo และ Foo บินไปรอบ ๆ เมื่อสิ่งที่พวกเขาต้องการจริงๆคือคลาส Foo และอาจเป็นโปรโตคอล Fooable

ส่วนหนึ่งของการทำให้แน่ใจว่าคุณไม่ทำสิ่งนี้คือการเข้าใจความแตกต่างในภาษาอย่างแท้จริง ตัวอย่างเช่นคุณไม่จำเป็นต้องใช้คลาส abstract และคลาส factory ด้านบนเนื่องจากเมธอดคลาส Objective-C ถูกส่งแบบไดนามิกเช่นเดียวกับวิธีการแบบอินสแตนซ์และสามารถแทนที่ได้ในคลาสย่อย


10
ในฐานะนักพัฒนา Java ผู้เขียนโรงงานนามธรรมใน Objective-C ฉันพบว่าสิ่งนี้น่าสนใจ คุณจะอธิบายเพิ่มเติมอีกเล็กน้อยเกี่ยวกับการทำงานของมัน - บางทีอาจเป็นตัวอย่าง
teabot

2
คุณยังเชื่อหรือไม่ว่าเราไม่ต้องการคลาสนามธรรมจากโรงงานตลอดเวลาที่ผ่านมานับตั้งแต่คุณโพสต์คำตอบนี้
kirk.burleson

50

ให้แน่ใจว่าคุณมาร์คแก้จุดบกพร่องเมจิกหน้า นี่ควรเป็นจุดแรกของคุณเมื่อปะทะหัวกับกำแพงในขณะที่พยายามหาต้นตอของข้อผิดพลาดโกโก้

ตัวอย่างเช่นมันจะบอกคุณถึงวิธีการค้นหาวิธีการที่คุณจัดสรรหน่วยความจำครั้งแรกในภายหลังว่าเป็นสาเหตุของการล่ม (เช่นในระหว่างการยกเลิกแอพ)


1
ขณะนี้มีหน้าDebugging Magicเฉพาะเวอร์ชัน iOS
Jeethu

38

พยายามหลีกเลี่ยงสิ่งที่ฉันตัดสินใจโทรหา เมื่อผู้มาใหม่เพื่อวัตถุประสงค์ -C ค้นพบหมวดหมู่พวกเขามักจะไปป่าหมูเพิ่มหมวดหมู่เล็ก ๆ น้อย ๆ ที่มีประโยชน์เพื่อทุกระดับในการดำรงอยู่ ( "คืออะไร? ฉันสามารถเพิ่มวิธีการแปลงหมายเลขเลขโรมันจะ NSNumber หินใน!" )

อย่าทำอย่างนี้

รหัสของคุณจะพกพาได้ง่ายขึ้นและเข้าใจได้ง่ายขึ้นโดยใช้วิธีการหมวดหมู่เล็ก ๆ น้อย ๆ นับสิบ ๆ ที่โปรยลงบนชั้นเรียนพื้นฐานสองโหล

ส่วนใหญ่เวลาที่คุณคิดว่าคุณต้องการวิธีการหมวดหมู่เพื่อช่วยปรับปรุงรหัสบางอย่างคุณจะพบว่าคุณไม่ต้องใช้วิธีการซ้ำอีก

มีอันตรายอื่น ๆ เช่นกันเว้นแต่คุณจะกำหนดวิธีการหมวดหมู่ของคุณ (และใครนอกเหนือจาก ddribin บ้าอย่างที่สุดคือ) มีโอกาสที่ Apple หรือปลั๊กอินหรือสิ่งอื่นที่ทำงานในพื้นที่ที่อยู่ของคุณจะกำหนดประเภทเดียวกัน วิธีการที่มีชื่อเดียวกันกับผลข้างเคียงที่แตกต่างกันเล็กน้อย ....

ตกลง. ตอนนี้คุณได้รับคำเตือนแล้วให้ข้าม "อย่าทำส่วนนี้" แต่การออกกำลังกายยับยั้งชั่งใจมาก


ฉันชอบคำตอบของคุณคำแนะนำของฉันจะไม่ใช้หมวดหมู่เพื่อจัดเก็บรหัสยูทิลิตี้เว้นแต่คุณกำลังจะทำซ้ำรหัสในสถานที่มากกว่าหนึ่งแห่งและรหัสอย่างชัดเจนอยู่ในชั้นเรียนที่คุณกำลังจะ categorfy ...
Kendall Helmstetter Gelner

ฉันเพียงต้องการที่จะไพเราะและเสียงสนับสนุนของฉันสำหรับวิธีการประเภท namespacing ดูเหมือนว่าสิ่งที่ถูกต้องที่จะทำ
Michael Buckley

+1 ถ้าตัวเลขโรมันเท่านั้น ฉันทำอย่างนั้นโดยสิ้นเชิง!
Brian Postow

14
จุดตอบโต้: สำหรับปีที่แล้วครึ่งหนึ่งที่ฉันได้ปฏิบัติตามนโยบายตรงข้ามที่แน่นอน: "หากสามารถนำไปใช้ในหมวดหมู่ได้ให้ทำเช่นนั้น" ผลที่ตามมาก็คือรหัสของฉันจะกระชับอ่านและเข้าใจง่ายกว่าโค้ดตัวอย่าง verbose ที่ Apple ให้มา ฉันได้สูญเสียความขัดแย้งของเนมสเปซเพียงครั้งเดียวประมาณ 10 นาทีและฉันอาจได้รับประสิทธิภาพในการสร้างตัวเองมาหลายเดือน สำหรับแต่ละคน แต่ฉันยอมรับนโยบายนี้เพื่อรับทราบความเสี่ยงและฉันดีใจอย่างยิ่งที่ฉันได้ทำ
cduhn

7
ฉันไม่เห็นด้วย ถ้ามันจะเป็นฟังก์ชั่นและมันใช้กับวัตถุพื้นฐานและคุณสามารถคิดถึงชื่อที่ดีติดอยู่ในหมวดหมู่ รหัสของคุณจะสามารถอ่านได้มากขึ้น ฉันคิดว่าจุดสำคัญจริงๆที่นี่คือ: ทำทุกอย่างในปริมาณที่พอเหมาะ
mxcl

37

ต่อต้านการซับคลาสโลก ในโกโก้มีการดำเนินการหลายอย่างผ่านการมอบหมายและการใช้งานรันไทม์ที่สำคัญซึ่งในเฟรมเวิร์กอื่น ๆ จะทำผ่านการทำคลาสย่อย

ตัวอย่างเช่นใน Java คุณใช้อินสแตนซ์ของ*Listenerคลาสย่อยที่ไม่ระบุชื่อมากและใน. NET คุณใช้EventArgsคลาสย่อยของคุณมาก ในโกโก้คุณไม่ได้ทำเช่นนั้น - ใช้การกระทำเป้าหมายแทน


6
หรือที่เรียกว่า "การประพันธ์ต่อการสืบทอด"
Andrew Ebling

37

เรียงลำดับสตริงตามที่ผู้ใช้ต้องการ

เมื่อคุณเรียงลำดับสตริงเพื่อแสดงต่อผู้ใช้คุณไม่ควรใช้compare:วิธีการง่าย ๆ แต่คุณควรใช้ภาษาท้องถิ่นวิธีการเปรียบเทียบเช่นหรือlocalizedCompare:localizedCaseInsensitiveCompare:

สำหรับรายละเอียดเพิ่มเติมโปรดดูที่การค้นหา, การเปรียบเทียบและเรียงลำดับสตริง


31

ประกาศคุณสมบัติ

โดยทั่วไปคุณควรใช้คุณสมบัติ Objective-C 2.0 Declared Properties สำหรับคุณสมบัติทั้งหมดของคุณ หากพวกเขาไม่สาธารณะเพิ่มพวกเขาในส่วนขยายชั้นเรียน การใช้คุณสมบัติที่ประกาศทำให้ความหมายการจัดการหน่วยความจำชัดเจนทันทีและทำให้ง่ายขึ้นสำหรับคุณที่จะตรวจสอบเมธอด dealloc ของคุณ - ถ้าคุณจัดกลุ่มการประกาศคุณสมบัติของคุณด้วยกันคุณสามารถสแกนได้อย่างรวดเร็วและเปรียบเทียบกับการใช้เมธอด dealloc ของคุณ

คุณควรคิดให้ถี่ถ้วนก่อนที่จะไม่ทำเครื่องหมายคุณสมบัติว่า 'ไม่ทำงาน' ในฐานะที่เป็นบันทึกคู่มือการเขียนโปรแกรมภาษา C วัตถุประสงค์คุณสมบัติเป็นอะตอมมิกตามค่าเริ่มต้นและมีค่าใช้จ่ายจำนวนมาก ยิ่งกว่านั้นการทำให้คุณสมบัติทั้งหมดของคุณเป็นแบบอะตอมมิกไม่ทำให้แอปพลิเคชันของคุณปลอดภัย นอกจากนี้โปรดทราบว่าหากคุณไม่ได้ระบุ 'nonatomic' และใช้วิธีการเข้าถึงของคุณเอง (แทนที่จะสังเคราะห์พวกเขา) คุณต้องใช้มันในแบบอะตอมมิก


26

คิดเกี่ยวกับค่าศูนย์

เช่น คำถามนี้บันทึกข้อความที่nilถูกต้องใน Objective-C ในขณะที่นี่เป็นข้อได้เปรียบบ่อยครั้ง - นำไปสู่การทำความสะอาดและเป็นธรรมชาติมากขึ้น - คุณสมบัติสามารถนำไปสู่ข้อผิดพลาดที่แปลกประหลาดและยากต่อการติดตามหากคุณได้รับnilค่าเมื่อคุณไม่ได้คาดหวัง


ฉันมีนี้#define SXRelease(o); o = nilและเช่นเดียวกันสำหรับและCFRelease freeทำให้ทุกอย่างง่ายขึ้น

26

ใช้ NSAssert และเพื่อน ๆ ฉันใช้ศูนย์เป็นวัตถุที่ถูกต้องตลอดเวลา ... โดยเฉพาะอย่างยิ่งการส่งข้อความถึงศูนย์ไม่มีผลสมบูรณ์ใน Obj-C อย่างไรก็ตามถ้าฉันต้องการตรวจสอบให้แน่ใจเกี่ยวกับสถานะของตัวแปรฉันใช้ NSAssert และ NSParameterAssert ซึ่งช่วยในการติดตามปัญหาได้อย่างง่ายดาย


1
ข้อมูลเพิ่มเติมที่นี่: developer.apple.com/mac/library/documentation/Cocoa/Reference/ … และที่นี่: stackoverflow.com/questions/2521275/what-is-nsparameterassert
Dave Gallagher

23

เรียบง่าย แต่ถูกลืม ตามข้อกำหนด:

โดยทั่วไปวิธีการในชั้นเรียนที่แตกต่างกันที่มีตัวเลือกเดียวกัน (ชื่อเดียวกัน) จะต้องใช้ร่วมกันกลับและประเภทอาร์กิวเมนต์ ข้อ จำกัด นี้ถูกกำหนดโดยคอมไพเลอร์เพื่ออนุญาตการเชื่อมโยงแบบไดนามิก

ในกรณีนี้ตัวเลือกชื่อที่เหมือนกันทั้งหมดแม้ว่าจะอยู่ในคลาสที่แตกต่างกันจะถูกพิจารณาว่ามีประเภทผลตอบแทน / อาร์กิวเมนต์ที่เหมือนกัน นี่คือตัวอย่างง่ายๆ

@interface FooInt:NSObject{}
-(int) print;
@end

@implementation FooInt
-(int) print{
    return 5;
}
@end

@interface FooFloat:NSObject{}
-(float) print;
@end

@implementation FooFloat
-(float) print{
    return 3.3;
}
@end

int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
    id f1=[[FooFloat alloc]init];
    //prints 0, runtime considers [f1 print] to return int, as f1's type is "id" and FooInt precedes FooBar
    NSLog(@"%f",[f1 print]);

    FooFloat* f2=[[FooFloat alloc]init];
    //prints 3.3 expectedly as the static type is FooFloat
    NSLog(@"%f",[f2 print]);

    [f1 release];
    [f2 release]
    [pool drain];

    return 0;
}   

มันง่ายที่จะลืม สิ่งสำคัญยังคงอยู่
Brock Woolf

3
นี่เป็นเพียงข้อกังวลเมื่อละเว้นจากการพิมพ์แบบคงที่ หากคอมไพเลอร์ทราบประเภทอาร์กิวเมนต์และประเภทส่งคืนอาจแตกต่างกันโดยไม่มีปัญหา โดยส่วนตัวแล้วฉันพบว่าสิ่งนี้มักจะไม่เป็นปัญหา Apple ยังมีวิธีการมากมายที่มีชื่อเหมือนกัน แต่แตกต่างกันในประเภทการคืนสินค้า ในที่สุดก็มีธงแปลเพื่อเตือนคุณในกรณีที่ไม่ชัดเจน
Nikolai Ruhe

หากเราปฏิบัติตามแนวทางการประชุมการตั้งชื่อแอปเปิ้ล, สถานการณ์เช่นนี้จะไม่เกิดขึ้น :)
Eonil

22

หากคุณใช้ Leopard (Mac OS X 10.5) หรือใหม่กว่าคุณสามารถใช้แอปพลิเคชั่นเครื่องมือในการค้นหาและติดตามการรั่วไหลของหน่วยความจำ หลังจากสร้างโปรแกรมของคุณใน Xcode แล้วให้เลือก Run> Start ด้วย Performance Tool> Leaks

แม้ว่าแอพของคุณจะไม่รั่วไหล แต่คุณอาจเก็บวัตถุไว้นานเกินไป ในเครื่องมือคุณสามารถใช้เครื่องมือ ObjectAlloc สำหรับสิ่งนี้ เลือกเครื่องมือ ObjectAlloc ในเอกสารเครื่องมือของคุณและแสดงรายละเอียดของเครื่องมือ (หากยังไม่ได้แสดง) โดยเลือกมุมมอง> รายละเอียด (ควรมีเครื่องหมายถูกอยู่ข้างๆ) ภายใต้ "อายุการจัดสรร" ในรายละเอียด ObjectAlloc ตรวจสอบให้แน่ใจว่าคุณเลือกปุ่มตัวเลือกถัดจาก "สร้างแล้วและยังมีชีวิตอยู่"

ตอนนี้เมื่อใดก็ตามที่คุณหยุดบันทึกแอปพลิเคชันของคุณการเลือกเครื่องมือ ObjectAlloc จะแสดงจำนวนการอ้างอิงที่มีต่อวัตถุที่ยังมีชีวิตอยู่ในแอปพลิเคชันของคุณในคอลัมน์ "# Net" ตรวจสอบให้แน่ใจว่าคุณไม่เพียง แต่ดูที่คลาสของคุณเอง แต่ยังรวมถึงคลาสของอ็อบเจ็กต์ระดับบนสุดของไฟล์ NIB ตัวอย่างเช่นถ้าคุณไม่มีหน้าต่างบนหน้าจอและคุณเห็นการอ้างอิงถึง NSWindow ที่ยังมีชีวิตอยู่คุณอาจไม่ได้เปิดตัวมันในรหัสของคุณ


21

ทำความสะอาดใน dealloc

นี่คือหนึ่งในสิ่งที่ง่ายที่สุดที่จะลืม - esp เมื่อการเข้ารหัสที่ 150mph เสมอเสมอทำความสะอาดคุณสมบัติ / ตัวแปรสมาชิกของคุณใน dealloc

ฉันชอบที่จะใช้คุณลักษณะ Objc 2 - ด้วยเครื่องหมายจุดใหม่ - ดังนั้นการล้างข้อมูลแบบไม่เจ็บปวด มักจะง่ายเหมือน:

- (void)dealloc
{
    self.someAttribute = NULL;
    [super dealloc];
}

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

เมื่อเปิดใช้งาน GC ใน 10.5 สิ่งนี้ไม่จำเป็นอีกต่อไป แต่คุณอาจต้องล้างทรัพยากรอื่น ๆ ที่คุณสร้างขึ้นคุณสามารถทำได้ในวิธีการสรุปแทน


12
โดยทั่วไปคุณไม่ควรใช้วิธีการเข้าถึงใน dealloc (หรือ init)
mmalc

1
นอกเหนือจากเหตุผลด้านประสิทธิภาพ (accessors ช้ากว่าการเข้าถึงโดยตรงเล็กน้อย) ทำไมฉันไม่ควรใช้ accessor ใน dealloc หรือ init
schwa

1
(a) เหตุผลด้านประสิทธิภาพเป็นเหตุผลที่เพียงพออย่างสมบูรณ์ในตัวเอง (โดยเฉพาะอย่างยิ่งถ้าอุปกรณ์ของคุณมีอะตอม) (b) คุณควรหลีกเลี่ยงผลข้างเคียงใด ๆ ที่ผู้เข้าถึงอาจมี หลังมีปัญหาโดยเฉพาะอย่างยิ่งถ้าคลาสของคุณอาจเป็นคลาสย่อย
mmalc

3
ฉันจะทราบว่าถ้าคุณกำลังทำงานบนรันไทม์ที่ทันสมัยด้วยไอวอรี่สังเคราะห์คุณต้องใช้ accessors ใน dealloc โค้ดรันไทม์สมัยใหม่จำนวนมากคือ GC แต่ไม่ใช่ทั้งหมด
Louis Gerbarg

1
มุมมองที่กว้างขึ้นเกี่ยวกับว่าจะไม่ใช้วิธี / คุณสมบัติ accessor ใน-initและ-deallocวิธีการสามารถดูได้ที่นี่: mikeash.com/?page=pyblog/…
Johan Kool

17

ความคิดเห็นทั้งหมดนี้ยอดเยี่ยม แต่ฉันประหลาดใจจริงๆที่ไม่มีใครพูดถึงObjective-C Style Guide ของ Googleที่ได้รับการตีพิมพ์ย้อนหลังไป ฉันคิดว่าพวกเขาได้ทำงานอย่างละเอียดมาก


7
อืมตัวอย่างแรกนั้นเต็มไปด้วยเรื่องไร้สาระ ไม่มีเอกสารสำนวนภาษา หากฉันพบความคิดเห็นประเภทนั้นในไฟล์ส่วนหัวฉันจะไม่รบกวนการอ่าน
Stephan Eggermont

5
ตาของฉัน !!!!! ฉันไม่อยากจะเชื่อในสิ่งที่ฉันเห็น
Eonil


13

อย่าลืมว่า NSWindowController และ NSViewController จะปล่อยวัตถุระดับบนสุดของไฟล์ NIB ที่ควบคุม

หากคุณโหลดไฟล์ NIB ด้วยตนเองคุณมีหน้าที่รับผิดชอบในการปล่อยออบเจ็กต์ระดับบนสุดของ NIB นั้นเมื่อคุณทำเสร็จแล้ว


12

สิ่งหนึ่งที่ค่อนข้างชัดเจนสำหรับผู้เริ่มต้นใช้: ใช้คุณลักษณะการเยื้องอัตโนมัติของ Xcode สำหรับรหัสของคุณ แม้ว่าคุณจะคัดลอก / วางจากแหล่งอื่นเมื่อคุณวางรหัสแล้วคุณสามารถเลือกบล็อกทั้งหมดของรหัสคลิกขวาที่มันแล้วเลือกตัวเลือกเพื่อเยื้องทุกอย่างในบล็อกนั้นอีกครั้ง

Xcode จะแยกวิเคราะห์ส่วนนั้นและเยื้องมันตามวงเล็บ, ลูป, ฯลฯ มันมีประสิทธิภาพมากขึ้นกว่าการกดปุ่ม space bar หรือแท็บคีย์สำหรับแต่ละบรรทัด


คุณสามารถตั้งค่า Tab ให้เยื้องจากนั้นทำ Cmd-A และ Tab
Plumenator

10

ฉันรู้ว่าฉันมองข้ามสิ่งนี้เมื่อเข้าสู่การเขียนโปรแกรม Cocoa เป็นครั้งแรก

ตรวจสอบให้แน่ใจว่าคุณเข้าใจความรับผิดชอบการจัดการหน่วยความจำที่เกี่ยวข้องกับไฟล์ NIB คุณมีความรับผิดชอบในการปล่อยวัตถุระดับบนสุดในไฟล์ NIB ใด ๆ ที่คุณโหลด อ่านเอกสารของ Appleในเรื่อง


6
นี่ไม่เป็นความจริง. ไม่ว่าคุณจะรับผิดชอบในการปล่อยวัตถุระดับบนสุดหรือไม่นั้นขึ้นอยู่กับคลาสที่คุณสืบทอดและคลาสที่คุณใช้ ดูdeveloper.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/…ท่ามกลางคนอื่น ๆ
mmalc

10

เปิดคำเตือน GCC ทั้งหมดจากนั้นปิดคำเตือนที่เกิดจากส่วนหัวของ Apple เป็นประจำเพื่อลดเสียงรบกวน

เรียกใช้การวิเคราะห์แบบคงที่ของเสียงดังกราวบ่อยครั้ง; คุณสามารถเปิดใช้งานได้สำหรับบิลด์ทั้งหมดผ่านการตั้งค่าบิลด์ "Run Static Analyzer"

เขียนการทดสอบหน่วยและรันด้วยแต่ละบิลด์


และหากเป็นไปได้ให้เปิด“ จัดการคำเตือนเป็นข้อผิดพลาด” ไม่อนุญาตให้มีการเตือน
ปีเตอร์ Hosey

2
สคริปต์ที่ใช้งานง่ายเพื่อตั้งค่าโครงการของคุณพร้อมคำเตือนที่แนะนำมีอยู่ที่นี่: rentzsch.tumblr.com/post/237349423/hoseyifyxcodewarnings-scpt
Johan Kool

10

ตัวแปรและคุณสมบัติ

1 / ทำให้ส่วนหัวของคุณสะอาดซ่อนการใช้งาน
อย่ารวมตัวแปรอินสแตนซ์ในส่วนหัวของคุณ ตัวแปรส่วนตัวที่นำไปใช้ในการเรียนต่อเนื่องเป็นคุณสมบัติ ตัวแปรสาธารณะประกาศเป็นคุณสมบัติสาธารณะในส่วนหัวของคุณ ถ้ามันควรจะอ่านเท่านั้นประกาศเป็นแบบอ่านอย่างเดียวและเขียนทับมันเป็น readwrite ในชั้นเรียนต่อเนื่อง โดยทั่วไปฉันไม่ได้ใช้ตัวแปรเลยคุณสมบัติเท่านั้น

2 / ให้ชื่อตัวแปรที่ไม่ใช่ค่าเริ่มต้นของคุณสมบัติตัวอย่าง:


@synthesize property = property_;

เหตุผลที่ 1: คุณจะพบข้อผิดพลาดที่เกิดจากการลืม "ตนเอง" เมื่อกำหนดคุณสมบัติ เหตุผลที่ 2: จากการทดสอบของฉัน Leak Analyzer ในเครื่องมือมีปัญหาในการตรวจจับการรั่วไหลของทรัพย์สินที่มีชื่อเริ่มต้น

3 / ไม่เคยใช้การเก็บรักษาหรือปล่อยโดยตรงกับคุณสมบัติ (หรือเฉพาะในสถานการณ์ที่พิเศษมาก) ใน dealloc ของคุณเพียงกำหนดศูนย์ รักษาคุณสมบัติมีไว้เพื่อจัดการรักษา / ปล่อยด้วยตนเอง คุณไม่มีทางรู้ได้ว่าตัวเซ็ตเตอร์ไม่ได้เพิ่มหรือลบผู้สังเกตการณ์ คุณควรใช้ตัวแปรโดยตรงภายใน setter และ getter

เข้าชม

1 / ใส่คำจำกัดความมุมมองทุกรายการลงใน xib หากทำได้ (ยกเว้นโดยปกติคือการตั้งค่าเนื้อหาและเลเยอร์แบบไดนามิก) ประหยัดเวลา (ง่ายกว่าการเขียนรหัส) ง่ายในการเปลี่ยนและรักษารหัสของคุณให้สะอาดอยู่เสมอ

2 / อย่าพยายามเพิ่มประสิทธิภาพการดูด้วยการลดจำนวนการดู อย่าสร้าง UIImageView ในรหัสของคุณแทนที่จะเป็น xib เพียงเพราะคุณต้องการเพิ่มการดูย่อยลงไป ใช้ UIImageView เป็นพื้นหลังแทน เฟรมเวิร์กมุมมองสามารถจัดการมุมมองนับร้อยโดยไม่มีปัญหา

3 / IBOutlets ไม่จำเป็นต้องเก็บรักษาไว้เสมอ (หรือแรง) โปรดทราบว่า IBOutlet ส่วนใหญ่ของคุณเป็นส่วนหนึ่งของลำดับชั้นการดูของคุณและเก็บรักษาไว้โดยปริยาย

4 / ปล่อย IBOutlets ทั้งหมดใน viewDidUnload

5 / โทร viewDidUnload จากเมธอด dealloc ของคุณ มันไม่ได้ถูกเรียกโดยปริยาย

หน่วยความจำ

1 / วัตถุ Autorelease เมื่อคุณสร้างพวกเขา ข้อบกพร่องหลายอย่างเกิดจากการย้ายสายเรียกเข้าของคุณเป็นหนึ่งใน if-else branch หรือหลังคำสั่ง return ควรใช้รีลีสแทนการวางจำหน่ายอัตโนมัติในกรณีพิเศษเช่นเมื่อคุณรอ runloop และคุณไม่ต้องการให้วัตถุของคุณถูก autorelease เร็วเกินไป

2 / แม้ว่าคุณจะใช้การนับการอ้างอิงอัตโนมัติคุณต้องเข้าใจอย่างถ่องแท้ว่าวิธีการเก็บรักษาแบบปล่อยทำงานได้อย่างไร การใช้รีลีส - รีลีสด้วยตนเองนั้นไม่ซับซ้อนกว่า ARC ในทั้งสองกรณีคุณต้องมีการรั่วไหลและการวนรอบ พิจารณาใช้การปล่อยเก็บไว้ด้วยตนเองในโครงการขนาดใหญ่หรือลำดับชั้นวัตถุที่ซับซ้อน

ความคิดเห็น

1 / สร้างรหัสของคุณโดยอัตโนมัติ ชื่อตัวแปรและชื่อเมธอดทุกตัวควรบอกสิ่งที่กำลังทำอยู่ หากเขียนรหัสอย่างถูกต้อง (คุณต้องฝึกฝนอย่างมากในเรื่องนี้) คุณไม่จำเป็นต้องแสดงความคิดเห็นเกี่ยวกับโค้ดใด ๆ (ไม่เหมือนกับความคิดเห็นเอกสารประกอบ) อัลกอริทึมอาจมีความซับซ้อน แต่รหัสควรเรียบง่ายอยู่เสมอ

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

รอยหยัก

1 / อย่าเพิ่มการเยื้องมากเกินไป ส่วนใหญ่ของรหัสวิธีการของคุณควรจะเยื้องในระดับวิธี บล็อกซ้อนกัน (ถ้ามีเป็นต้น) จะลดความสามารถในการอ่าน หากคุณมีบล็อกซ้อนกันสามบล็อกคุณควรลองใส่บล็อกด้านในเป็นวิธีแยกต่างหาก ไม่ควรใช้บล็อกซ้อนกันสี่บล็อกหรือมากกว่า หากส่วนใหญ่ของรหัสวิธีการของคุณอยู่ภายในของ if, ปฏิเสธเงื่อนไข if ตัวอย่าง:


if (self) {
   //... long initialization code ...
}

return self;

if (!self) {
   return nil;
}

//... long initialization code ...

return self;

ทำความเข้าใจกับรหัส C ส่วนใหญ่เป็นโครงสร้าง C

โปรดทราบว่า Obj-C เป็นเพียงเลเยอร์ OOP ที่เบากว่าภาษา C คุณควรเข้าใจว่าโครงสร้างโค้ดพื้นฐานใน C ทำงานอย่างไร (enums, structs, array, pointers และอื่น ๆ ) ตัวอย่าง:


view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20);

เหมือนกับ:


CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;

และอื่น ๆ อีกมากมาย

ปรับปรุงเอกสารมาตรฐานการเข้ารหัสของคุณเองและอัปเดตบ่อยครั้ง พยายามเรียนรู้จากข้อบกพร่องของคุณ ทำความเข้าใจว่าเหตุใดข้อผิดพลาดจึงถูกสร้างขึ้นและพยายามหลีกเลี่ยงปัญหานี้โดยใช้มาตรฐานการเข้ารหัส

ปัจจุบันมาตรฐานการเข้ารหัสของเรามีประมาณ 20 หน้าการผสมผสานของมาตรฐานการเข้ารหัสของ Java มาตรฐาน Google Obj-C / C ++ และการเพิ่มเติมของเราเอง เอกสารรหัสของคุณใช้เยื้องมาตรฐานมาตรฐานช่องว่างสีขาวและบรรทัดว่างเปล่าในสถานที่ที่เหมาะสม ฯลฯ


9

จะมีมากขึ้นการทำงาน

Objective-C เป็นภาษาเชิงวัตถุ แต่ตระหนักถึงกรอบการทำงานของสไตล์โกโก้และได้รับการออกแบบสไตล์การทำงานในหลาย ๆ กรณี

  1. มีการแบ่งแยกความแปรปรวน ใช้คลาสที่ไม่เปลี่ยนรูปเป็นวัตถุหลักและวัตถุที่ไม่แน่นอนเป็นรอง ตัวอย่างเช่นใช้ NSArray เป็นหลักและใช้ NSMutableArray เฉพาะเมื่อคุณต้องการ

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

อย่างไรก็ตามอย่ากลัวที่จะใช้ฟังก์ชั่นที่ไม่บริสุทธิ์เช่นกัน

  1. มีการประเมินผลที่ขี้เกียจ ดูสิ่งที่ชอบ-[UIViewController view]ทรัพย์สิน มุมมองจะไม่ถูกสร้างขึ้นเมื่อมีการสร้างวัตถุ มันจะถูกสร้างขึ้นเมื่อผู้โทรอ่านviewคุณสมบัติในครั้งแรก UIImageจะไม่ถูกโหลดจนกว่าจะถูกวาดจริง มีการนำไปใช้หลายอย่างเช่นการออกแบบนี้ การออกแบบประเภทนี้มีประโยชน์มากสำหรับการจัดการทรัพยากร แต่ถ้าคุณไม่ทราบแนวคิดของการประเมินที่ขี้เกียจมันไม่ง่ายที่จะเข้าใจพฤติกรรมของพวกเขา

  2. มีการปิด ใช้บล็อก C มากที่สุด สิ่งนี้จะทำให้ชีวิตของคุณง่ายขึ้นอย่างมาก แต่อ่านอีกครั้งเกี่ยวกับการจัดการบล็อกหน่วยความจำก่อนที่จะใช้

  3. มี GC แบบกึ่งอัตโนมัติ NSAutoreleasePool ใช้งาน-autoreleaseหลัก ใช้คู่มือ-retain/-releaseรองเมื่อคุณต้องการจริงๆ (เช่นการเพิ่มประสิทธิภาพหน่วยความจำการลบทรัพยากรอย่างชัดเจน)


2
ในฐานะที่เป็น 3) ฉันจะนำเสนอวิธีการที่ตรงกันข้าม: ใช้รักษาด้วยตนเอง / ปล่อยทุกที่ที่ทำได้ ใครจะรู้ว่าจะใช้รหัสนี้อย่างไร - และหากใช้ในวงแคบ ๆ ใคร ๆ ก็สามารถระเบิดการใช้หน่วยความจำของคุณได้โดยไม่จำเป็น
Eiko

@Eiko นั่นเป็นเพียงการเพิ่มประสิทธิภาพก่อนกำหนดไม่สามารถเป็นแนวทางทั่วไปได้
Eonil

1
ฉันคิดว่ามันเป็นเรื่องของการออกแบบมากกว่าโดยเฉพาะเมื่อทำงานกับคลาสของแบบจำลอง ฉันคิดว่าการเพิ่มหน่วยความจำเป็นผลข้างเคียงและนั่นไม่ใช่สิ่งที่ฉันต้องการให้ปรากฏบ่อยครั้ง ที่แย่กว่านั้นนักพัฒนารายอื่นที่ใช้รหัสของฉันไม่มีโอกาสนอกจากจะตัดการโทรราคาแพงลงในกลุ่มการกู้คืนอัตโนมัติ (ถ้าเป็นไปได้วัตถุของฉันอาจถูกส่งไปยังรหัสห้องสมุดอื่น ๆ ) และปัญหาเหล่านั้นยากที่จะวินิจฉัยในภายหลัง แต่ราคาถูกเพื่อหลีกเลี่ยงในสถานที่แรก หากคุณคัดลอก / ลบอัตโนมัติวัตถุที่ผ่านเข้าไปแล้วคุณอาจหลงทางถ้ามันใหญ่กว่าที่คุณคาดไว้มาก แม้ว่าฉันจะผ่อนคลายมากขึ้นด้วยรหัส GUI แต่
Eiko

@Eiko ฉันเห็นด้วยautoreleaseจะถือหน่วยความจำได้นานกว่าและคู่มือretain/releaseสามารถลดปริมาณการใช้หน่วยความจำได้ อย่างไรก็ตามควรเป็นแนวทางสำหรับการเพิ่มประสิทธิภาพของกรณีพิเศษ (แม้คุณจะรู้สึกอยู่เสมอ!) ไม่สามารถเป็นเหตุผลในการฝึกให้เหมาะสมก่อนวัยอันควรได้เช่นกัน และที่จริงข้อเสนอแนะของคุณไม่ตรงข้ามกับฉัน ที่ผมกล่าวถึงว่ามันเป็นกรณีที่จำเป็นจริงๆ :)
Eonil
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.