ฉันรู้เกี่ยวกับHIG (ซึ่งค่อนข้างมีประโยชน์!) แต่คุณใช้วิธีการเขียนโปรแกรมแบบใดเมื่อเขียน Objective-C และเฉพาะเจาะจงมากขึ้นเมื่อใช้ Cocoa (หรือ CocoaTouch)
ฉันรู้เกี่ยวกับHIG (ซึ่งค่อนข้างมีประโยชน์!) แต่คุณใช้วิธีการเขียนโปรแกรมแบบใดเมื่อเขียน Objective-C และเฉพาะเจาะจงมากขึ้นเมื่อใช้ Cocoa (หรือ CocoaTouch)
คำตอบ:
มีบางสิ่งที่ฉันเริ่มทำซึ่งฉันไม่คิดว่าเป็นมาตรฐาน:
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
เมื่อเมธอดหรือฟังก์ชั่นรับอาร์กิวเมนต์สตริงรูปแบบคุณควรตรวจสอบให้แน่ใจว่าคุณสามารถควบคุมเนื้อหาของสตริงรูปแบบได้
ตัวอย่างเช่นเมื่อบันทึกสตริงการดึงดูดให้ส่งผ่านตัวแปรสตริงเป็นอาร์กิวเมนต์เพียงอย่างเดียวNSLog
คือ:
NSString *aString = // get a string from somewhere;
NSLog(aString);
ปัญหานี้คือว่าสตริงอาจมีตัวละครที่ถูกตีความว่าเป็นสตริงรูปแบบ สิ่งนี้สามารถนำไปสู่ผลลัพธ์ที่ผิดพลาดขัดข้องและปัญหาด้านความปลอดภัย คุณควรแทนที่ตัวแปรสตริงเป็นสตริงรูปแบบแทน
NSLog(@"%@", aString);
ใช้การตั้งชื่อโกโก้มาตรฐานและการจัดรูปแบบอนุสัญญาและคำศัพท์แทนสิ่งที่คุณคุ้นเคยจากสภาพแวดล้อมอื่น มีนักพัฒนาโกโก้อยู่มากมายและเมื่ออีกคนหนึ่งเริ่มทำงานกับโค้ดของคุณมันจะเข้าถึงได้ง่ายกว่าถ้ามันดูและรู้สึกคล้ายกับโค้ดโกโก้อื่น ๆ
ตัวอย่างของสิ่งที่ต้องทำและสิ่งที่ไม่ควรทำ:
id m_something;
ในอินเตอร์เฟซของวัตถุและเรียกมันว่าตัวแปรสมาชิกหรือข้อมูล ; ใช้something
หรือ_something
สำหรับชื่อและเรียกมันว่าตัวแปรเช่น-getSomething
; -something
ชื่อโกโก้ที่เหมาะสมเป็นเพียง-something:
; มันควรจะเป็น-setSomething:
-[NSObject performSelector:withObject:]
NSObject::performSelector
ไม่ว่าคุณจะทำอะไรอย่าใช้ Win16 / Win32-style สัญกรณ์ฮังการี แม้แต่ไมโครซอฟท์ก็ยอมแพ้ในเรื่องนี้ด้วยการย้ายไปยังแพลตฟอร์ม. NET
ในอดีตการจัดการหน่วยความจำของร้านไม่ดี แนวปฏิบัติที่ดีที่สุดในปัจจุบันคือการประกาศร้านค้าเป็นคุณสมบัติ:
@interface MyClass :NSObject {
NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end
การใช้คุณสมบัติทำให้ซีแมนทิกส์การจัดการหน่วยความจำชัดเจน มันยังให้รูปแบบที่สอดคล้องกันถ้าคุณใช้การสังเคราะห์ตัวแปรอินสแตนซ์
หมายเหตุ: ภายใต้ Xcode 4 ตอนนี้ถูกสร้างขึ้นใน IDE
คุณใช้Clang Static Analyzerเพื่อ - ไม่น่าแปลกใจ - วิเคราะห์ C และรหัส Objective-C ของคุณ (ยังไม่มี C ++) บน Mac OS X 10.5 มันง่ายที่จะติดตั้งและใช้งาน:
cd
ไปยังไดเรกทอรีโครงการของคุณscan-build -k -V xcodebuild
ปฏิบัติ(มีข้อ จำกัด เพิ่มเติมบางอย่าง ฯลฯ โดยเฉพาะอย่างยิ่งคุณควรวิเคราะห์โครงการในการกำหนดค่า "Debug" - ดูที่http://clang.llvm.org/StaticAnalysisUsage.html http://clang.llvm.org/StaticAnalysisUsage.htmlเพื่อดูรายละเอียด - แต่ก็มากหรือน้อย สิ่งที่เดือดลงไป)
จากนั้นเครื่องวิเคราะห์จะสร้างชุดของหน้าเว็บสำหรับคุณซึ่งแสดงถึงการจัดการหน่วยความจำที่เป็นไปได้และปัญหาพื้นฐานอื่น ๆ ที่คอมไพเลอร์ไม่สามารถตรวจพบได้
อันนี้บอบบาง แต่มีประโยชน์ 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;
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.
nil == NULL
@NaveenShan พวกเขาจะตรงเดียวกันยกเว้นว่าnil
เป็นid
และเป็นNULL
void *
ใบแจ้งยอดของคุณไม่เป็นความจริง
@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 ระดับต้น"
ดังนั้นพวกเขาจึงเป็นส่วนหนึ่งของชั้นเรียนจริง - และไม่ใช่หมวดหมู่ (ส่วนตัว) นอกเหนือจากชั้นเรียน ความแตกต่างที่ลึกซึ้ง แต่สำคัญ
()
แทน(Private)
(หรือชื่อหมวดหมู่อื่น ๆ ): คุณสามารถประกาศคุณสมบัติเป็นแบบอ่านเขียนในขณะที่สู่สาธารณะโดยจะเป็นแบบอ่านอย่างเดียวเท่านั้น :)
เนื่องจากปกติแล้วคุณ (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
NSAutoreleasePool
หากพวกเขาเพิ่มรอยความทรงจำโดยมากเกินไปคุณควรใช้อีก แต่หลังจากคุณยืนยันว่านี่เป็นปัญหาจริงๆ การเพิ่มประสิทธิภาพก่อนวัยและทุกอย่าง ...
บางส่วนได้ถูกกล่าวถึงไปแล้ว แต่นี่คือสิ่งที่ฉันสามารถนึกได้จากส่วนบนของหัว:
#pragma mark [section]
ใช้ โดยปกติฉันจะจัดกลุ่มตามวิธีการของฉันเองการแทนที่แต่ละคลาสย่อยและข้อมูลหรือโปรโตคอลที่เป็นทางการ มันทำให้ง่ายขึ้นมากที่จะข้ามไปยังสิ่งที่ฉันกำลังมองหา ในหัวข้อเดียวกันให้จัดกลุ่มวิธีการที่คล้ายกัน (เช่นวิธีการมอบหมายของมุมมองตาราง) เข้าด้วยกันไม่เพียง แต่ติดไว้ที่ใดก็ได้#define
ทำตามใจชอบหรือแคชอาร์เรย์แทนที่จะเรียงลำดับทุกครั้งที่ต้องการข้อมูล มีหลายสิ่งที่ฉันสามารถพูดเกี่ยวกับเรื่องนี้ได้ แต่บรรทัดล่างจะไม่เขียนโค้ดจนกว่าคุณจะต้องการมันหรือผู้สร้างโปรไฟล์บอกคุณ มันทำให้การบำรุงรักษาง่ายขึ้นในระยะยาวNSLog( @"stub" )
ข้างในหรือคุณต้องการติดตามสิ่งต่างๆFinish what you start
คุณยังสามารถใช้// TODO:
เพื่อทำเครื่องหมายรหัสให้เสร็จซึ่งจะปรากฏในรายการแบบหล่นลง
เขียนการทดสอบหน่วย คุณสามารถทดสอบจำนวนมากของสิ่งที่อยู่ในโกโก้ที่อาจจะยากในกรอบอื่น ๆ ตัวอย่างเช่นด้วยรหัส UI คุณสามารถยืนยันได้ว่ามีการเชื่อมต่อสิ่งต่าง ๆ ตามที่ควรเชื่อใจได้ว่าจะทำงานเมื่อมีการใช้งาน และคุณสามารถตั้งค่าสถานะ & เรียกใช้เมธอดตัวแทนได้อย่างง่ายดายเพื่อทดสอบ
นอกจากนี้คุณยังไม่มีการมองเห็นแบบสาธารณะและแบบที่ได้รับการป้องกันเทียบกับวิธีส่วนตัวที่จะได้รับในการเขียนแบบทดสอบสำหรับภายใน
กฎทอง: ถ้าคุณalloc
แล้วคุณrelease
!
อัปเดต: ยกเว้นว่าคุณกำลังใช้งาน ARC อยู่
copy
, mutableCopy
, หรือnew
retain
อย่าเขียน Objective-C ราวกับว่าเป็น Java / C # / C ++ / etc
ฉันเคยเห็นทีมที่เคยเขียนโปรแกรมเว็บ Java EE ลองเขียนแอปพลิเคชัน Cocoa บนเดสก์ท็อป ราวกับว่ามันเป็นเว็บแอปพลิเคชัน Java EE มี AbstractFooFactory และ FooFactory มากมายและ IFoo และ Foo บินไปรอบ ๆ เมื่อสิ่งที่พวกเขาต้องการจริงๆคือคลาส Foo และอาจเป็นโปรโตคอล Fooable
ส่วนหนึ่งของการทำให้แน่ใจว่าคุณไม่ทำสิ่งนี้คือการเข้าใจความแตกต่างในภาษาอย่างแท้จริง ตัวอย่างเช่นคุณไม่จำเป็นต้องใช้คลาส abstract และคลาส factory ด้านบนเนื่องจากเมธอดคลาส Objective-C ถูกส่งแบบไดนามิกเช่นเดียวกับวิธีการแบบอินสแตนซ์และสามารถแทนที่ได้ในคลาสย่อย
ให้แน่ใจว่าคุณมาร์คแก้จุดบกพร่องเมจิกหน้า นี่ควรเป็นจุดแรกของคุณเมื่อปะทะหัวกับกำแพงในขณะที่พยายามหาต้นตอของข้อผิดพลาดโกโก้
ตัวอย่างเช่นมันจะบอกคุณถึงวิธีการค้นหาวิธีการที่คุณจัดสรรหน่วยความจำครั้งแรกในภายหลังว่าเป็นสาเหตุของการล่ม (เช่นในระหว่างการยกเลิกแอพ)
พยายามหลีกเลี่ยงสิ่งที่ฉันตัดสินใจโทรหา เมื่อผู้มาใหม่เพื่อวัตถุประสงค์ -C ค้นพบหมวดหมู่พวกเขามักจะไปป่าหมูเพิ่มหมวดหมู่เล็ก ๆ น้อย ๆ ที่มีประโยชน์เพื่อทุกระดับในการดำรงอยู่ ( "คืออะไร? ฉันสามารถเพิ่มวิธีการแปลงหมายเลขเลขโรมันจะ NSNumber หินใน!" )
อย่าทำอย่างนี้
รหัสของคุณจะพกพาได้ง่ายขึ้นและเข้าใจได้ง่ายขึ้นโดยใช้วิธีการหมวดหมู่เล็ก ๆ น้อย ๆ นับสิบ ๆ ที่โปรยลงบนชั้นเรียนพื้นฐานสองโหล
ส่วนใหญ่เวลาที่คุณคิดว่าคุณต้องการวิธีการหมวดหมู่เพื่อช่วยปรับปรุงรหัสบางอย่างคุณจะพบว่าคุณไม่ต้องใช้วิธีการซ้ำอีก
มีอันตรายอื่น ๆ เช่นกันเว้นแต่คุณจะกำหนดวิธีการหมวดหมู่ของคุณ (และใครนอกเหนือจาก ddribin บ้าอย่างที่สุดคือ) มีโอกาสที่ Apple หรือปลั๊กอินหรือสิ่งอื่นที่ทำงานในพื้นที่ที่อยู่ของคุณจะกำหนดประเภทเดียวกัน วิธีการที่มีชื่อเดียวกันกับผลข้างเคียงที่แตกต่างกันเล็กน้อย ....
ตกลง. ตอนนี้คุณได้รับคำเตือนแล้วให้ข้าม "อย่าทำส่วนนี้" แต่การออกกำลังกายยับยั้งชั่งใจมาก
ต่อต้านการซับคลาสโลก ในโกโก้มีการดำเนินการหลายอย่างผ่านการมอบหมายและการใช้งานรันไทม์ที่สำคัญซึ่งในเฟรมเวิร์กอื่น ๆ จะทำผ่านการทำคลาสย่อย
ตัวอย่างเช่นใน Java คุณใช้อินสแตนซ์ของ*Listener
คลาสย่อยที่ไม่ระบุชื่อมากและใน. NET คุณใช้EventArgs
คลาสย่อยของคุณมาก ในโกโก้คุณไม่ได้ทำเช่นนั้น - ใช้การกระทำเป้าหมายแทน
เมื่อคุณเรียงลำดับสตริงเพื่อแสดงต่อผู้ใช้คุณไม่ควรใช้compare:
วิธีการง่าย ๆ แต่คุณควรใช้ภาษาท้องถิ่นวิธีการเปรียบเทียบเช่นหรือlocalizedCompare:
localizedCaseInsensitiveCompare:
สำหรับรายละเอียดเพิ่มเติมโปรดดูที่การค้นหา, การเปรียบเทียบและเรียงลำดับสตริง
โดยทั่วไปคุณควรใช้คุณสมบัติ Objective-C 2.0 Declared Properties สำหรับคุณสมบัติทั้งหมดของคุณ หากพวกเขาไม่สาธารณะเพิ่มพวกเขาในส่วนขยายชั้นเรียน การใช้คุณสมบัติที่ประกาศทำให้ความหมายการจัดการหน่วยความจำชัดเจนทันทีและทำให้ง่ายขึ้นสำหรับคุณที่จะตรวจสอบเมธอด dealloc ของคุณ - ถ้าคุณจัดกลุ่มการประกาศคุณสมบัติของคุณด้วยกันคุณสามารถสแกนได้อย่างรวดเร็วและเปรียบเทียบกับการใช้เมธอด dealloc ของคุณ
คุณควรคิดให้ถี่ถ้วนก่อนที่จะไม่ทำเครื่องหมายคุณสมบัติว่า 'ไม่ทำงาน' ในฐานะที่เป็นบันทึกคู่มือการเขียนโปรแกรมภาษา C วัตถุประสงค์คุณสมบัติเป็นอะตอมมิกตามค่าเริ่มต้นและมีค่าใช้จ่ายจำนวนมาก ยิ่งกว่านั้นการทำให้คุณสมบัติทั้งหมดของคุณเป็นแบบอะตอมมิกไม่ทำให้แอปพลิเคชันของคุณปลอดภัย นอกจากนี้โปรดทราบว่าหากคุณไม่ได้ระบุ 'nonatomic' และใช้วิธีการเข้าถึงของคุณเอง (แทนที่จะสังเคราะห์พวกเขา) คุณต้องใช้มันในแบบอะตอมมิก
เช่น คำถามนี้บันทึกข้อความที่nil
ถูกต้องใน Objective-C ในขณะที่นี่เป็นข้อได้เปรียบบ่อยครั้ง - นำไปสู่การทำความสะอาดและเป็นธรรมชาติมากขึ้น - คุณสมบัติสามารถนำไปสู่ข้อผิดพลาดที่แปลกประหลาดและยากต่อการติดตามหากคุณได้รับnil
ค่าเมื่อคุณไม่ได้คาดหวัง
ใช้ NSAssert และเพื่อน ๆ ฉันใช้ศูนย์เป็นวัตถุที่ถูกต้องตลอดเวลา ... โดยเฉพาะอย่างยิ่งการส่งข้อความถึงศูนย์ไม่มีผลสมบูรณ์ใน Obj-C อย่างไรก็ตามถ้าฉันต้องการตรวจสอบให้แน่ใจเกี่ยวกับสถานะของตัวแปรฉันใช้ NSAssert และ NSParameterAssert ซึ่งช่วยในการติดตามปัญหาได้อย่างง่ายดาย
เรียบง่าย แต่ถูกลืม ตามข้อกำหนด:
โดยทั่วไปวิธีการในชั้นเรียนที่แตกต่างกันที่มีตัวเลือกเดียวกัน (ชื่อเดียวกัน) จะต้องใช้ร่วมกันกลับและประเภทอาร์กิวเมนต์ ข้อ จำกัด นี้ถูกกำหนดโดยคอมไพเลอร์เพื่ออนุญาตการเชื่อมโยงแบบไดนามิก
ในกรณีนี้ตัวเลือกชื่อที่เหมือนกันทั้งหมดแม้ว่าจะอยู่ในคลาสที่แตกต่างกันจะถูกพิจารณาว่ามีประเภทผลตอบแทน / อาร์กิวเมนต์ที่เหมือนกัน นี่คือตัวอย่างง่ายๆ
@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;
}
หากคุณใช้ Leopard (Mac OS X 10.5) หรือใหม่กว่าคุณสามารถใช้แอปพลิเคชั่นเครื่องมือในการค้นหาและติดตามการรั่วไหลของหน่วยความจำ หลังจากสร้างโปรแกรมของคุณใน Xcode แล้วให้เลือก Run> Start ด้วย Performance Tool> Leaks
แม้ว่าแอพของคุณจะไม่รั่วไหล แต่คุณอาจเก็บวัตถุไว้นานเกินไป ในเครื่องมือคุณสามารถใช้เครื่องมือ ObjectAlloc สำหรับสิ่งนี้ เลือกเครื่องมือ ObjectAlloc ในเอกสารเครื่องมือของคุณและแสดงรายละเอียดของเครื่องมือ (หากยังไม่ได้แสดง) โดยเลือกมุมมอง> รายละเอียด (ควรมีเครื่องหมายถูกอยู่ข้างๆ) ภายใต้ "อายุการจัดสรร" ในรายละเอียด ObjectAlloc ตรวจสอบให้แน่ใจว่าคุณเลือกปุ่มตัวเลือกถัดจาก "สร้างแล้วและยังมีชีวิตอยู่"
ตอนนี้เมื่อใดก็ตามที่คุณหยุดบันทึกแอปพลิเคชันของคุณการเลือกเครื่องมือ ObjectAlloc จะแสดงจำนวนการอ้างอิงที่มีต่อวัตถุที่ยังมีชีวิตอยู่ในแอปพลิเคชันของคุณในคอลัมน์ "# Net" ตรวจสอบให้แน่ใจว่าคุณไม่เพียง แต่ดูที่คลาสของคุณเอง แต่ยังรวมถึงคลาสของอ็อบเจ็กต์ระดับบนสุดของไฟล์ NIB ตัวอย่างเช่นถ้าคุณไม่มีหน้าต่างบนหน้าจอและคุณเห็นการอ้างอิงถึง NSWindow ที่ยังมีชีวิตอยู่คุณอาจไม่ได้เปิดตัวมันในรหัสของคุณ
ทำความสะอาดใน dealloc
นี่คือหนึ่งในสิ่งที่ง่ายที่สุดที่จะลืม - esp เมื่อการเข้ารหัสที่ 150mph เสมอเสมอทำความสะอาดคุณสมบัติ / ตัวแปรสมาชิกของคุณใน dealloc
ฉันชอบที่จะใช้คุณลักษณะ Objc 2 - ด้วยเครื่องหมายจุดใหม่ - ดังนั้นการล้างข้อมูลแบบไม่เจ็บปวด มักจะง่ายเหมือน:
- (void)dealloc
{
self.someAttribute = NULL;
[super dealloc];
}
สิ่งนี้จะดูแลรีลีสสำหรับคุณและตั้งค่าแอ็ตทริบิวต์เป็น NULL (ซึ่งฉันพิจารณาการตั้งโปรแกรมการป้องกัน - ในกรณีที่วิธีการอื่นใน dealloc เข้าถึงตัวแปรสมาชิกอีกครั้ง - หายาก แต่อาจทำได้เกิดขึ้นได้)
เมื่อเปิดใช้งาน GC ใน 10.5 สิ่งนี้ไม่จำเป็นอีกต่อไป แต่คุณอาจต้องล้างทรัพยากรอื่น ๆ ที่คุณสร้างขึ้นคุณสามารถทำได้ในวิธีการสรุปแทน
-init
และ-dealloc
วิธีการสามารถดูได้ที่นี่: mikeash.com/?page=pyblog/…
ความคิดเห็นทั้งหมดนี้ยอดเยี่ยม แต่ฉันประหลาดใจจริงๆที่ไม่มีใครพูดถึงObjective-C Style Guide ของ Googleที่ได้รับการตีพิมพ์ย้อนหลังไป ฉันคิดว่าพวกเขาได้ทำงานอย่างละเอียดมาก
นอกจากนี้หัวข้อกึ่งที่เกี่ยวข้อง (ที่มีห้องสำหรับคำตอบเพิ่มเติม!):
เคล็ดลับและเทคนิค Xcode เล็กน้อยเหล่านี้ที่คุณต้องการให้คุณรู้เมื่อประมาณ 2 ปีที่แล้วคืออะไร? .
อย่าลืมว่า NSWindowController และ NSViewController จะปล่อยวัตถุระดับบนสุดของไฟล์ NIB ที่ควบคุม
หากคุณโหลดไฟล์ NIB ด้วยตนเองคุณมีหน้าที่รับผิดชอบในการปล่อยออบเจ็กต์ระดับบนสุดของ NIB นั้นเมื่อคุณทำเสร็จแล้ว
สิ่งหนึ่งที่ค่อนข้างชัดเจนสำหรับผู้เริ่มต้นใช้: ใช้คุณลักษณะการเยื้องอัตโนมัติของ Xcode สำหรับรหัสของคุณ แม้ว่าคุณจะคัดลอก / วางจากแหล่งอื่นเมื่อคุณวางรหัสแล้วคุณสามารถเลือกบล็อกทั้งหมดของรหัสคลิกขวาที่มันแล้วเลือกตัวเลือกเพื่อเยื้องทุกอย่างในบล็อกนั้นอีกครั้ง
Xcode จะแยกวิเคราะห์ส่วนนั้นและเยื้องมันตามวงเล็บ, ลูป, ฯลฯ มันมีประสิทธิภาพมากขึ้นกว่าการกดปุ่ม space bar หรือแท็บคีย์สำหรับแต่ละบรรทัด
ฉันรู้ว่าฉันมองข้ามสิ่งนี้เมื่อเข้าสู่การเขียนโปรแกรม Cocoa เป็นครั้งแรก
ตรวจสอบให้แน่ใจว่าคุณเข้าใจความรับผิดชอบการจัดการหน่วยความจำที่เกี่ยวข้องกับไฟล์ NIB คุณมีความรับผิดชอบในการปล่อยวัตถุระดับบนสุดในไฟล์ NIB ใด ๆ ที่คุณโหลด อ่านเอกสารของ Appleในเรื่อง
เปิดคำเตือน GCC ทั้งหมดจากนั้นปิดคำเตือนที่เกิดจากส่วนหัวของ Apple เป็นประจำเพื่อลดเสียงรบกวน
เรียกใช้การวิเคราะห์แบบคงที่ของเสียงดังกราวบ่อยครั้ง; คุณสามารถเปิดใช้งานได้สำหรับบิลด์ทั้งหมดผ่านการตั้งค่าบิลด์ "Run Static Analyzer"
เขียนการทดสอบหน่วยและรันด้วยแต่ละบิลด์
ตัวแปรและคุณสมบัติ
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 ++ และการเพิ่มเติมของเราเอง เอกสารรหัสของคุณใช้เยื้องมาตรฐานมาตรฐานช่องว่างสีขาวและบรรทัดว่างเปล่าในสถานที่ที่เหมาะสม ฯลฯ
จะมีมากขึ้นการทำงาน
Objective-C เป็นภาษาเชิงวัตถุ แต่ตระหนักถึงกรอบการทำงานของสไตล์โกโก้และได้รับการออกแบบสไตล์การทำงานในหลาย ๆ กรณี
มีการแบ่งแยกความแปรปรวน ใช้คลาสที่ไม่เปลี่ยนรูปเป็นวัตถุหลักและวัตถุที่ไม่แน่นอนเป็นรอง ตัวอย่างเช่นใช้ NSArray เป็นหลักและใช้ NSMutableArray เฉพาะเมื่อคุณต้องการ
มีฟังก์ชั่นบริสุทธิ์ ไม่มากซื้อ API เฟรมเวิร์กจำนวนมากที่ออกแบบมาเหมือนฟังก์ชั่นแท้ ดูที่ฟังก์ชั่นเช่นหรือCGRectMake()
CGAffineTransformMake()
เห็นได้ชัดว่ารูปแบบตัวชี้มีประสิทธิภาพมากขึ้น อย่างไรก็ตามการโต้แย้งทางอ้อมกับพอยน์เตอร์ไม่สามารถเสนอผลข้างเคียงได้ฟรี โครงสร้างการออกแบบอย่างหมดจดมากที่สุด แยกวัตถุสถานะแม้กระทั่ง ใช้-copy
แทน-retain
เมื่อส่งค่าไปยังวัตถุอื่น เนื่องจากสถานะที่ใช้ร่วมกันสามารถมีอิทธิพลต่อการกลายพันธุ์ของมูลค่าในวัตถุอื่น ๆ อย่างเงียบ ๆ ดังนั้นจึงไม่สามารถปราศจากผลข้างเคียง หากคุณมีค่าจากภายนอกจากวัตถุให้คัดลอก ดังนั้นจึงเป็นเรื่องสำคัญที่ต้องมีการออกแบบสถานะการแชร์ให้น้อยที่สุด
อย่างไรก็ตามอย่ากลัวที่จะใช้ฟังก์ชั่นที่ไม่บริสุทธิ์เช่นกัน
มีการประเมินผลที่ขี้เกียจ ดูสิ่งที่ชอบ-[UIViewController view]
ทรัพย์สิน มุมมองจะไม่ถูกสร้างขึ้นเมื่อมีการสร้างวัตถุ มันจะถูกสร้างขึ้นเมื่อผู้โทรอ่านview
คุณสมบัติในครั้งแรก UIImage
จะไม่ถูกโหลดจนกว่าจะถูกวาดจริง มีการนำไปใช้หลายอย่างเช่นการออกแบบนี้ การออกแบบประเภทนี้มีประโยชน์มากสำหรับการจัดการทรัพยากร แต่ถ้าคุณไม่ทราบแนวคิดของการประเมินที่ขี้เกียจมันไม่ง่ายที่จะเข้าใจพฤติกรรมของพวกเขา
มีการปิด ใช้บล็อก C มากที่สุด สิ่งนี้จะทำให้ชีวิตของคุณง่ายขึ้นอย่างมาก แต่อ่านอีกครั้งเกี่ยวกับการจัดการบล็อกหน่วยความจำก่อนที่จะใช้
มี GC แบบกึ่งอัตโนมัติ NSAutoreleasePool ใช้งาน-autorelease
หลัก ใช้คู่มือ-retain/-release
รองเมื่อคุณต้องการจริงๆ (เช่นการเพิ่มประสิทธิภาพหน่วยความจำการลบทรัพยากรอย่างชัดเจน)
autorelease
จะถือหน่วยความจำได้นานกว่าและคู่มือretain/release
สามารถลดปริมาณการใช้หน่วยความจำได้ อย่างไรก็ตามควรเป็นแนวทางสำหรับการเพิ่มประสิทธิภาพของกรณีพิเศษ (แม้คุณจะรู้สึกอยู่เสมอ!) ไม่สามารถเป็นเหตุผลในการฝึกให้เหมาะสมก่อนวัยอันควรได้เช่นกัน และที่จริงข้อเสนอแนะของคุณไม่ตรงข้ามกับฉัน ที่ผมกล่าวถึงว่ามันเป็นกรณีที่จำเป็นจริงๆ :)