Các thực tiễn tốt nhất mà bạn sử dụng khi viết Objective-C và Ca cao là gì? [đóng cửa]


346

Tôi biết về HIG (khá tiện dụng!), Nhưng bạn sử dụng thực hành lập trình nào khi viết Objective-C, và cụ thể hơn là khi sử dụng Cacao (hoặc CacaoTouch).


Xem bài đăng blog này, rất tốt đẹp. ironwolf.dangerousgames.com/blog/archives/913
user392412

Câu trả lời:


398

Có một vài điều tôi đã bắt đầu làm mà tôi không nghĩ là chuẩn:

1) Với sự ra đời của các thuộc tính, tôi không còn sử dụng các biến lớp "_" để tiền tố "riêng tư". Rốt cuộc, nếu một biến khác có thể được truy cập bởi các lớp khác thì không nên có thuộc tính cho nó? Tôi luôn không thích tiền tố "_" để làm cho mã xấu hơn, và bây giờ tôi có thể loại bỏ nó.

2) Nói về những điều riêng tư, tôi thích đặt các định nghĩa phương thức riêng tư trong tệp .m trong một phần mở rộng lớp như vậy:

#import "MyClass.h"

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

@implementation MyClass

Tại sao làm lộn xộn tệp .h với những thứ mà người ngoài không nên quan tâm? Trống () hoạt động cho các danh mục riêng tư trong tệp .m và đưa ra các cảnh báo biên dịch nếu bạn không triển khai các phương thức được khai báo.

3) Tôi đã thực hiện đặt dealloc ở đầu tệp .m, ngay bên dưới các chỉ thị @synthesize. Không phải những gì bạn giải quyết sẽ đứng đầu danh sách những điều bạn muốn nghĩ về một lớp học? Điều đó đặc biệt đúng trong một môi trường như iPhone.

3.5) Trong các ô của bảng, làm cho mọi phần tử (bao gồm cả chính ô) mờ đi để thực hiện. Điều đó có nghĩa là thiết lập màu nền thích hợp trong mọi thứ.

3.6) Khi sử dụng kết nối NSURLC, theo quy tắc, bạn có thể muốn thực hiện phương thức ủy nhiệm:

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

Tôi thấy hầu hết các cuộc gọi web đều rất đơn lẻ và đó là ngoại lệ hơn so với quy tắc bạn sẽ muốn phản hồi được lưu trong bộ nhớ cache, đặc biệt là đối với các cuộc gọi dịch vụ web. Việc thực hiện phương pháp như được hiển thị sẽ vô hiệu hóa bộ đệm ẩn của các phản hồi.

Cũng đáng quan tâm, là một số lời khuyên cụ thể về iPhone tốt từ Joseph Mattiello (nhận được trong danh sách gửi thư của iPhone). Có nhiều hơn, nhưng đây là những thứ hữu ích nhất mà tôi nghĩ (lưu ý rằng một vài bit hiện đã được chỉnh sửa một chút so với bản gốc để bao gồm các chi tiết được cung cấp trong phản hồi):

4) Chỉ sử dụng độ chính xác gấp đôi nếu bạn phải, chẳng hạn như khi làm việc với CoreLocation. Hãy chắc chắn rằng bạn kết thúc các hằng số của mình trong 'f' để làm cho gcc lưu trữ chúng dưới dạng phao.

float val = someFloat * 2.2f;

Điều này chủ yếu quan trọng khi someFloatthực sự có thể là gấp đôi, bạn không cần toán học ở chế độ hỗn hợp, vì bạn đang mất độ chính xác trong 'val' khi lưu trữ. Mặc dù số dấu phẩy động được hỗ trợ trong phần cứng trên iPhone, nhưng vẫn có thể mất nhiều thời gian hơn để thực hiện số học có độ chính xác kép so với độ chính xác đơn. Người giới thiệu:

Trên các điện thoại cũ được cho là các phép tính hoạt động ở cùng tốc độ nhưng bạn có thể có nhiều thành phần chính xác đơn hơn trong các thanh ghi hơn gấp đôi, do đó, đối với nhiều phép tính, độ chính xác đơn sẽ kết thúc nhanh hơn.

5) Đặt thuộc tính của bạn là nonatomic. Họ đang atomictheo mặc định và sau khi tổng hợp, semaphore mã sẽ được tạo ra để ngăn chặn vấn đề đa luồng. 99% trong số bạn có thể không cần phải lo lắng về điều này và mã ít bị cồng kềnh và tiết kiệm bộ nhớ hơn khi được đặt thành không phổ biến.

6) SQLite có thể là một cách rất, rất nhanh để lưu trữ các tập dữ liệu lớn. Ví dụ, một ứng dụng bản đồ có thể lưu trữ các ô của nó vào các tệp SQLite. Phần đắt nhất là đĩa I / O. Tránh viết nhiều bằng cách gửi BEGIN;COMMIT;giữa các khối lớn. Chúng tôi sử dụng bộ đếm thời gian 2 giây, ví dụ, đặt lại trên mỗi lần gửi mới. Khi nó hết hạn, chúng tôi gửi CAM KẾT; , khiến cho tất cả các bài viết của bạn đi trong một đoạn lớn. SQLite lưu trữ dữ liệu giao dịch vào đĩa và thực hiện gói Bắt đầu / Kết thúc này để tránh tạo nhiều tệp giao dịch, nhóm tất cả các giao dịch vào một tệp.

Ngoài ra, SQL sẽ chặn GUI của bạn nếu nó nằm trên luồng chính của bạn. Nếu bạn có một truy vấn rất dài, thì nên lưu trữ các truy vấn của bạn dưới dạng các đối tượng tĩnh và chạy SQL của bạn trên một luồng riêng biệt. Đảm bảo bọc bất cứ thứ gì sửa đổi cơ sở dữ liệu cho các chuỗi truy vấn theo @synchronize() {}khối. Đối với các truy vấn ngắn, chỉ cần để lại những thứ trên luồng chính để thuận tiện hơn.

Có nhiều mẹo tối ưu hóa SQLite hơn ở đây, mặc dù tài liệu xuất hiện rất nhiều điểm có thể vẫn còn tốt;

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


3
Mẹo hay về số học đôi.
Adam Ernst

8
Các tiện ích mở rộng lớp hiện là cách ưa thích cho các phương thức riêng tư: developer.apple.com/Mac/l
Library / documentation / Coloa / Conceptionual / Kẻ

9
Lời khuyên của bạn về việc nhân đôi trên iPhone đã hết hạn stackoverflow.com/questions/1622729/ory
Casebash

3
Không hết hạn; hoàn toàn sai: iPhone ban đầu được hỗ trợ nổi và tăng gấp đôi phần cứng với tốc độ xấp xỉ nhau. SQLite cũng không giữ các giao dịch trong bộ nhớ; họ đã ghi nhật ký trên đĩa. Chỉ các truy vấn dài chặn giao diện người dùng của bạn; Nó ít lộn xộn hơn để chạy mọi thứ trong luồng chính và sử dụng các truy vấn nhanh hơn.
tc.

1
@tc: Tôi đã sửa mục SQL về các giao dịch, lưu ý rằng bản thân tôi đã không viết bốn mục cuối đó. Tôi cũng đã làm rõ phần về việc di chuyển các truy vấn sang nền chỉ dành cho các truy vấn rất dài (đôi khi bạn không thể rút ngắn chúng lại). Nhưng để gọi toàn bộ điều "sai" vì một vài điểm là tôi cảm thấy khá cực đoan. Ngoài ra, câu trả lời ở trên đã nêu: "Trên các điện thoại cũ được cho là tính toán hoạt động ở cùng tốc độ" nhưng lưu ý phần về số lượng lớn hơn các thanh ghi chính xác duy nhất khiến chúng vẫn thích hợp hơn.
Kendall Helmstetter Gelner

109

Không sử dụng các chuỗi không xác định làm chuỗi định dạng

Khi các phương thức hoặc hàm có một đối số chuỗi định dạng, bạn nên đảm bảo rằng bạn có quyền kiểm soát nội dung của chuỗi định dạng.

Ví dụ: khi ghi nhật ký chuỗi, việc truyền biến chuỗi là đối số duy nhất cho NSLog:

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

Vấn đề với điều này là chuỗi có thể chứa các ký tự được hiểu là chuỗi định dạng. Điều này có thể dẫn đến đầu ra sai, sự cố và vấn đề bảo mật. Thay vào đó, bạn nên thay thế biến chuỗi thành chuỗi định dạng:

    NSLog(@"%@", aString);

4
Tôi đã bị cắn bởi cái này trước đây.
Adam Ernst

Đây là lời khuyên tốt cho mọi ngôn ngữ lập trình
Tom Fobear

107

Sử dụng các quy ước và thuật ngữ định dạng và đặt tên ca cao tiêu chuẩn hơn là bất cứ điều gì bạn đã sử dụng từ môi trường khác. Có rất nhiều các nhà phát triển ca cao trên mạng, và khi người khác trong số họ bắt đầu làm việc với mã của bạn, nó sẽ được nhiều dễ tiếp cận hơn nếu nó trông và cảm thấy tương tự để mã Cocoa khác.

Ví dụ về những việc cần làm và không nên làm:

  • Không khai báo id m_something;trong giao diện của đối tượng và gọi nó là biến thành viên hoặc trường ; sử dụng somethinghoặc _somethingcho tên của nó và gọi nó là một biến thể hiện .
  • Đừng đặt tên cho một getter -getSomething; tên ca cao thích hợp là chỉ -something.
  • Đừng đặt tên cho một setter -something:; nó nên-setSomething:
  • Tên phương thức được xen kẽ với các đối số và bao gồm dấu hai chấm; đó là -[NSObject performSelector:withObject:], không phải NSObject::performSelector.
  • Sử dụng inter-caps (CamelCase) trong tên phương thức, tham số, biến, tên lớp, v.v. chứ không phải underbars (dấu gạch dưới).
  • Tên lớp bắt đầu bằng một chữ cái viết hoa, tên biến và tên phương thức với chữ thường.

Dù bạn có làm gì đi nữa, đừng sử dụng ký hiệu Hungary kiểu Win16 / Win32. Ngay cả Microsoft đã từ bỏ điều đó với việc chuyển sang nền tảng .NET.


5
Tôi sẽ tranh luận, đừng sử dụng setS Something: / Something gì đó - thay vào đó hãy sử dụng các thuộc tính. Tại thời điểm này, có rất ít người thực sự cần phải nhắm mục tiêu Tiger (lý do duy nhất không sử dụng tài sản)
Kendall Helmstetter Gelner

18
Các thuộc tính vẫn tạo các phương thức truy cập cho bạn và các thuộc tính getter = / setter = trên thuộc tính cho phép bạn chỉ định tên của các phương thức. Ngoài ra, bạn có thể sử dụng cú pháp [foo Something] thay vì cú pháp foo.s Something với các thuộc tính. Vì vậy, đặt tên accessor vẫn có liên quan.
Chris Hanson

3
Đây là một tài liệu tham khảo tuyệt vời cho ai đó đến từ C ++, nơi tôi đã làm hầu hết những điều bạn khuyên.
Clinton Blackmore

4
Một setter không nên gây ra một cái gì đó được lưu vào cơ sở dữ liệu. Có một lý do Core Data có phương thức -save: trên NSManagedObjectContext, thay vì setters tạo các bản cập nhật ngay lập tức.
Chris Hanson

2
Tôi nghi ngờ đó không phải là một lựa chọn, tuy nhiên nó có thể phải xem lại kiến ​​trúc ứng dụng của bạn. (Để rõ ràng: Tôi không nói "Bạn nên sử dụng Dữ liệu cốt lõi." Tôi đang nói "Setters không nên lưu vào cơ sở dữ liệu.") Có bối cảnh để quản lý biểu đồ đối tượng, thay vì lưu các đối tượng riêng lẻ trong đó , hầu như luôn luôn là cả hai có thể và một giải pháp tốt hơn.
Chris Hanson

106

IBOutlets

Trong lịch sử, quản lý bộ nhớ của các cửa hàng là kém. Thực tiễn tốt nhất hiện nay là khai báo các cửa hàng là tài sản:

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

Sử dụng các thuộc tính làm cho ngữ nghĩa quản lý bộ nhớ rõ ràng; nó cũng cung cấp một mẫu nhất quán nếu bạn sử dụng tổng hợp biến thể hiện.


1
Sẽ không tải nib giữ nó hai lần sau đó? (một lần trong ngòi, lần thứ hai bằng cách gán cho tài sản). Tôi có nên phát hành những người trong dealloc?
Kornel

6
Bạn phải xử lý các ổ cắm trong viewDidUnload (iPhone OS 3.0+) hoặc trong phương thức setView: tùy chỉnh để tránh rò rỉ. Rõ ràng bạn cũng nên phát hành trong dealloc.
Frank Szczerba

2
Hãy nhớ rằng không phải ai cũng đồng ý với phong cách này: weblog.bignerdranch.com/?p=95
Michael

Đây là cách Apple làm mọi thứ quá. "Bắt đầu phát triển iPhone 3" cũng đề cập đến sự thay đổi này so với các phiên bản trước.
ustun

Tôi đã đề cập đến vấn đề này trong một bình luận khác, nhưng đáng lẽ nên đặt nó ở đây: Một khi quá trình tổng hợp ivar động bắt đầu xảy ra đối với các ứng dụng iOS (nếu / khi nào?), Bạn sẽ rất vui khi bạn đặt IBOutlet trên tài sản so với ivar!
Joe D'Andrea

97

Sử dụng Trình phân tích tĩnh LLVM / Clang

LƯU Ý: Trong Xcode 4, phần này hiện được tích hợp vào IDE.

Bạn sử dụng Trình phân tích tĩnh Clang để - không ngạc nhiên - phân tích mã C và Objective-C của bạn (chưa có C ++) trên Mac OS X 10.5. Việc cài đặt và sử dụng không quan trọng

  1. Tải về phiên bản mới nhất từ trang này .
  2. Từ dòng lệnh, cdđến thư mục dự án của bạn.
  3. Thực thi scan-build -k -V xcodebuild.

(Có một số ràng buộc bổ sung, v.v., đặc biệt bạn nên phân tích một dự án trong cấu hình "Gỡ lỗi" của nó - xem http://clang.llvm.org/StaticAnalysisUsage.html để biết chi tiết - nhưng ít nhiều những gì nó sôi lên.)

Sau đó, bộ phân tích tạo ra một tập hợp các trang web cho bạn thấy khả năng quản lý bộ nhớ và các vấn đề cơ bản khác mà trình biên dịch không thể phát hiện được.


1
Tôi đã gặp một số khó khăn khi làm việc này cho đến khi tôi làm theo các hướng dẫn sau: Oiledmachine.com/posts/2009/01/06/ mẹo
bbrown

15
Trong XCode 3.2.1 trên Snow Leopard, nó đã được tích hợp sẵn. Bạn có thể chạy thủ công, sử dụng Run -> Build and Phân tích hoặc bạn có thể bật nó cho tất cả các bản dựng thông qua cài đặt xây dựng "Chạy phân tích tĩnh". Lưu ý rằng công cụ này hiện chỉ hỗ trợ C và Objective-C, nhưng không hỗ trợ C ++ / Objective-C ++.
oefe

94

Đây là một trong những tinh tế nhưng tiện dụng một. Nếu bạn tự chuyển mình làm đại biểu cho đối tượng khác, hãy đặt lại đại biểu của đối tượng đó trước bạn dealloc.

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

Bằng cách này, bạn đảm bảo rằng sẽ không có thêm phương thức ủy nhiệm nào được gửi. Khi bạn sắp deallocvà biến mất trong ether, bạn muốn chắc chắn rằng không có gì có thể gửi cho bạn thêm bất kỳ tin nhắn nào một cách tình cờ. Hãy nhớ self.someObject có thể được giữ lại bởi một đối tượng khác (nó có thể là một người độc thân hoặc trên nhóm tự động hoặc bất cứ điều gì) và cho đến khi bạn nói với nó "ngừng gửi tin nhắn cho tôi!", Nó nghĩ rằng đối tượng sắp bị xử lý của bạn là trò chơi công bằng.

Tập thói quen này sẽ giúp bạn tránh khỏi nhiều sự cố kỳ lạ gây khó chịu.

Hiệu trưởng tương tự áp dụng cho Quan sát giá trị chính và NSNotifying cũng vậy.

Biên tập:

Thậm chí phòng thủ hơn, thay đổi:

self.someObject.delegate = NULL;

vào:

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

8
Không có gì tinh tế về điều này, tài liệu nói rõ rằng bạn bắt buộc phải làm điều này. Từ 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

Tốt hơn hết là sử dụng nil thay vì NULL, vì NULL sẽ không giải phóng bộ nhớ.
Naveen Shan

@NaveenShan nil == NULL. Chúng giống hệt nhau ngoại trừ đó nillà một idNULLlà một void *. Tuyên bố của bạn không đúng.

@WTP yep, nil == NULL, nhưng sử dụng nil rõ ràng là cách ưa thích, nếu bạn xem qua các đoạn mã ví dụ của táo, họ đang sử dụng nil ở mọi nơi và như bạn đã nói, nil là một id, khiến nó thích hợp hơn khoảng trống * , trong trường hợp bạn gửi id, đó là.
Ahti

1
@Ahti chính xác, và Nil(chữ hoa) là loại Class*. Mặc dù tất cả đều bằng nhau, nhưng sử dụng sai có thể gây ra các lỗi nhỏ khó chịu, đặc biệt là trong Objective-C ++.

86

@kendell

Thay vì:

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

Sử dụng:

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

Mới trong Mục tiêu-C 2.0.

Các tiện ích mở rộng lớp được mô tả trong Tài liệu tham khảo Objective-C 2.0 của Apple.

"Tiện ích mở rộng lớp cho phép bạn khai báo API cần thiết bổ sung cho một lớp ở các vị trí khác ngoài khối chính @interface"

Vì vậy, chúng là một phần của lớp thực tế - và KHÔNG phải là một loại (riêng tư) ngoài lớp. Sự khác biệt tinh tế nhưng quan trọng.


Bạn có thể làm điều đó nhưng tôi thích gắn nhãn rõ ràng là phần "riêng tư" (nhiều tài liệu hơn chức năng) mặc dù tất nhiên điều đó rất rõ ràng từ nó nằm trong tệp .m ...
Kendall Helmstetter Gelner

2
Ngoại trừ có một sự khác biệt giữa các chủng loại riêng và mở rộng lớp: "mở rộng lớp cho phép bạn khai báo thêm API cần thiết cho một lớp học tại các địa điểm khác so với trong khối lớp @ interface tiểu học, như minh họa trong ví dụ sau:" Thấy chưa liên kết trong chỉnh sửa.
schwa

Tôi đồng ý có một sự khác biệt trong đó trình biên dịch sẽ cảnh báo bạn khi bạn chưa triển khai các phương thức CE - nhưng tôi không thấy khía cạnh đó rất quan trọng khi tất cả các phương thức nằm trong cùng một tệp và tất cả đều riêng tư. Tôi vẫn thích khía cạnh bảo trì của việc đánh dấu khối tham chiếu chuyển tiếp riêng tư
Kendall Helmstetter Gelner

3
Tôi thực sự không thấy (Riêng tư) là bất kỳ duy trì nhiều hơn (). Nếu bạn lo lắng thì một lượng bình luận tốt có thể giúp ích. Nhưng rõ ràng là sống và hãy sống. YMMV, v.v.
schwa

17
Có một lợi thế khá quan trọng để sử dụng ()thay vì(Private) (hoặc một số tên danh mục khác): Bạn có thể xác định lại các thuộc tính dưới dạng đọc trong khi công khai chúng chỉ đọc. :)
Pascal

75

Tránh tự động

Vì bạn thường (1) không có quyền kiểm soát trực tiếp trong suốt cuộc đời của họ, các đối tượng được tự động phát hành có thể tồn tại trong một thời gian tương đối dài và làm tăng một cách không cần thiết bộ nhớ ứng dụng của bạn. Trong khi trên máy tính để bàn, điều này có thể gây ra ít hậu quả, trên các nền tảng bị hạn chế hơn, đây có thể là một vấn đề quan trọng. Do đó, trên tất cả các nền tảng và đặc biệt là trên các nền tảng bị hạn chế hơn, nên tránh sử dụng các phương pháp dẫn đến các đối tượng tự động và thay vào đó, bạn nên sử dụng mô hình cấp phát / init.

Do đó, thay vì:

aVariable = [AClass convenienceMethod];

nơi có thể, thay vào đó bạn nên sử dụng:

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

Khi bạn đang viết các phương thức của riêng mình để trả về một đối tượng mới được tạo, bạn có thể tận dụng quy ước đặt tên của Cacao để gắn cờ cho người nhận rằng nó phải được phát hành bằng cách thêm tên phương thức bằng "mới".

Do đó, thay vì:

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

bạn có thể viết:

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

Vì tên phương thức bắt đầu bằng "mới", người tiêu dùng API của bạn biết rằng họ chịu trách nhiệm giải phóng đối tượng đã nhận (ví dụ: xem, ví dụ: newObject phương thức của NSObjectContoder ).

(1) Bạn có thể kiểm soát bằng cách sử dụng nhóm tự động điền địa phương của riêng bạn. Để biết thêm về điều này, xem Autorelease Pools .


6
Tôi thấy những lợi ích của việc không sử dụng autorelease lớn hơn chi phí của nó (tức là nhiều lỗi rò rỉ bộ nhớ hơn). Mã trên luồng chính dù sao cũng phải chạy khá ngắn (hoặc nếu không, bạn sẽ đóng băng giao diện người dùng) và đối với mã nền sử dụng nhiều bộ nhớ, chạy lâu hơn, bạn luôn có thể bọc các phần sử dụng nhiều bộ nhớ trong các vùng tự động cục bộ.
adib

56
Tôi không đồng ý. Bạn nên sử dụng các đối tượng tự động bất cứ khi nào có thể. Nếu chúng làm tăng dung lượng bộ nhớ quá nhiều, bạn nên sử dụng cái khác NSAutoreleasePool. Nhưng chỉ sau khi bạn xác nhận rằng đây thực sự là một vấn đề. Tối ưu hóa sớm và tất cả những thứ đó ...
Sven

3
Tôi dành ít hơn 40 giây. một ngày gõ [phát hành someObject] và đọc "dòng bổ sung" khi khởi tạo một đối tượng mới, nhưng tôi đã từng đốt cháy trong 17 giờ để tìm một lỗi tự động chỉ xuất hiện trong các trường hợp đặc biệt và không có lỗi kết hợp trong bảng điều khiển. Vì vậy, tôi đồng ý với adib khi anh ấy nói rằng "Tôi thấy lợi ích của việc không sử dụng autorelease vượt xa chi phí của nó".
RickiG

7
Tôi đồng ý với Sven. Mục tiêu chính phải là sự rõ ràng về mã và giảm lỗi mã hóa, chỉ tối ưu hóa bộ nhớ khi cần thiết. Nhập một [[[Foo alloc] init] autorelease] là nhanh chóng và bạn ngay lập tức xử lý vấn đề phát hành đối tượng mới này. Khi đọc mã, bạn không cần phải tìm kiếm bản phát hành tương ứng để đảm bảo rằng nó không bị rò rỉ.
Mike Weller

3
Vòng đời của các đối tượng tự động được xác định rõ và có thể xác định ở mức đủ.
Eonil

69

Một số trong số này đã được đề cập, nhưng đây là những gì tôi có thể nghĩ ra khỏi đỉnh đầu:

  • Thực hiện theo quy tắc đặt tên KVO.Ngay cả khi bạn không sử dụng KVO ngay bây giờ, theo kinh nghiệm của tôi, đôi khi nó vẫn có lợi trong tương lai. Và nếu bạn đang sử dụng KVO hoặc các ràng buộc, bạn cần biết mọi thứ đang hoạt động theo đúng nghĩa của chúng. Điều này không chỉ bao gồm các phương thức truy cập và các biến đối tượng, mà còn bao gồm nhiều mối quan hệ, xác thực, tự động thông báo các khóa phụ thuộc, v.v.
  • Đặt phương thức riêng tư trong một thể loại. Không chỉ giao diện, mà việc thực hiện là tốt. Thật tốt khi có một số khoảng cách về mặt khái niệm giữa các phương pháp riêng tư và không riêng tư. Tôi bao gồm mọi thứ trong tập tin .m của tôi.
  • Đặt phương thức chủ đề nền trong một thể loại. Giống như trên. Tôi thấy thật tốt khi giữ một rào cản khái niệm rõ ràng khi bạn nghĩ về những gì trên luồng chính và những gì không.
  • Sử dụng #pragma mark [section]. Thông thường tôi nhóm theo các phương thức của riêng tôi, các phần ghi đè của mỗi lớp con và bất kỳ thông tin hoặc giao thức chính thức nào. Điều này làm cho nó dễ dàng hơn nhiều để chuyển đến chính xác những gì tôi đang tìm kiếm. Trong cùng một chủ đề, nhóm các phương thức tương tự (như các phương thức ủy nhiệm của chế độ xem bảng) với nhau, không chỉ dán chúng ở bất cứ đâu.
  • Tiền tố phương thức riêng tư & ivars với _. Tôi thích vẻ ngoài của nó, và tôi ít sử dụng ngà voi khi tôi có nghĩa là một tài sản tình cờ.
  • Không sử dụng các phương thức / thuộc tính của trình biến đổi trong init & dealloc.Tôi chưa bao giờ có điều gì xấu xảy ra vì nó, nhưng tôi có thể thấy logic nếu bạn thay đổi phương thức để làm điều gì đó phụ thuộc vào trạng thái của đối tượng của bạn.
  • Đặt IBOutlets vào tài sản. Tôi thực sự chỉ đọc cái này ở đây, nhưng tôi sẽ bắt đầu làm nó. Bất kể lợi ích bộ nhớ, nó có vẻ tốt hơn về mặt phong cách (ít nhất là với tôi).
  • Tránh viết mã bạn không thực sự cần. Điều này thực sự bao gồm rất nhiều thứ, như tạo ra ngà khi #definesẽ làm hoặc lưu trữ một mảng thay vì sắp xếp nó mỗi khi cần dữ liệu. Có rất nhiều điều tôi có thể nói về điều này, nhưng điểm mấu chốt là không viết mã cho đến khi bạn cần nó, hoặc trình hồ sơ cho bạn biết. Nó làm cho mọi thứ dễ dàng hơn nhiều để duy trì trong thời gian dài.
  • Kết thúc những gì bạn bắt đầu. Có rất nhiều kết thúc, mã lỗi là cách nhanh nhất để giết chết một dự án. Nếu bạn cần một phương pháp sơ khai vẫn ổn, chỉ cần chỉ ra bằng cách đặt NSLog( @"stub" )bên trong, hoặc tuy nhiên bạn muốn theo dõi mọi thứ.

3
Tôi khuyên bạn nên đặt các phương thức riêng tư trong phần tiếp theo của lớp. (ví dụ @interface MyClass () ... @end in .m của bạn)
Jason Medeiros

3
Thay vì #PRAGMA, bạn có thể sử dụng một nhận xét // Đánh dấu: [Phần] dễ mang theo hơn và hoạt động giống hệt nhau.
aleemb

Trừ khi tôi thiếu một cú pháp đặc biệt, // Đánh dấu: không thêm nhãn trong trình đơn thả xuống của các chức năng của Xcode, đây thực sự là một nửa lý do sử dụng nó.
Marc Charbonneau

6
Bạn cần sử dụng chữ hoa, "// Mark: ...", để làm cho nó hiển thị trong trình đơn thả xuống.
Rhult

3
Liên quan đến Finish what you startbạn cũng có thể sử dụng // TODO:để đánh dấu mã để hoàn thành sẽ hiển thị trong trình đơn thả xuống.
iwasrobbed

56

Viết bài kiểm tra đơn vị. Bạn có thể kiểm tra rất nhiều thứ trong Ca cao có thể khó hơn trong các khung khác. Ví dụ: với mã UI, bạn thường có thể xác minh rằng mọi thứ được kết nối như bình thường và tin tưởng rằng chúng sẽ hoạt động khi được sử dụng. Và bạn có thể thiết lập trạng thái & gọi các phương thức ủy nhiệm một cách dễ dàng để kiểm tra chúng.

Bạn cũng không có khả năng hiển thị công khai so với bảo vệ so với phương thức riêng tư trong cách viết bài kiểm tra cho nội bộ của bạn.


Những khung kiểm tra nào bạn đề nghị?
melfar

13
Xcode bao gồm OCUnit, khung thử nghiệm đơn vị Objective-C và hỗ trợ để chạy các gói thử nghiệm đơn vị như một phần của quy trình xây dựng của bạn.
Chris Hanson

55

Nguyên tắc vàng: Nếu bạn allocthì bạn release!

CẬP NHẬT: Trừ khi bạn đang sử dụng ARC


26
Ngoài ra nếu bạn copy, mutableCopy, newhoặc retain.
Sven

54

Đừng viết Objective-C như thể nó là Java / C # / C ++ / etc.

Tôi đã từng thấy một nhóm được sử dụng để viết các ứng dụng web Java EE cố gắng viết một ứng dụng máy tính để bàn. Như thể đó là một ứng dụng web Java EE. Có rất nhiều AbstractFooFactory và FooFactory và IFoo và Foo bay xung quanh khi tất cả những gì họ thực sự cần là một lớp Foo và có thể là một giao thức Fooable.

Một phần của việc đảm bảo bạn không làm điều này là thực sự hiểu được sự khác biệt trong ngôn ngữ. Ví dụ, bạn không cần các lớp nhà máy và nhà máy trừu tượng ở trên vì các phương thức lớp Objective-C được gửi một cách linh hoạt như các phương thức cá thể và có thể được ghi đè trong các lớp con.


10
Là một nhà phát triển Java, người đã viết một nhà máy trừu tượng trong Objective-C, tôi thấy điều này rất hấp dẫn. Bạn có phiền giải thích thêm một chút về cách thức hoạt động của nó - có lẽ với một ví dụ?
teabot

2
Bạn có tin rằng chúng ta không cần các lớp học trừu tượng sau tất cả thời gian đã qua kể từ khi bạn đăng câu trả lời này không?
kirk.burleson

50

Hãy chắc chắn rằng bạn đánh dấu trang gỡ lỗi Magic . Đây phải là điểm dừng đầu tiên của bạn khi đập đầu vào tường trong khi cố gắng tìm ra nguồn gốc của lỗi Cacao.

Ví dụ, nó sẽ cho bạn biết cách tìm phương thức mà lần đầu tiên bạn cấp phát bộ nhớ mà sau đó gây ra sự cố (như trong khi chấm dứt ứng dụng).


1
Hiện tại đã có phiên bản dành riêng cho iOS của trang gỡ lỗi Magic .
Jeethu

38

Cố gắng tránh những gì tôi đã quyết định gọi Newbiec Categoryaholism. Khi những người mới tham gia Objective-C khám phá các danh mục, họ thường phát cuồng, thêm các danh mục nhỏ hữu ích cho mọi lớp đang tồn tại ( "Cái gì? Tôi có thể thêm một phương thức để chuyển đổi một số thành chữ số La Mã thành đá NSNumber trên!" ).

Đừng làm điều này.

Mã của bạn sẽ dễ mang theo hơn và dễ hiểu hơn với hàng tá phương thức danh mục nhỏ được rắc lên trên hai chục lớp nền tảng.

Hầu hết thời gian khi bạn thực sự nghĩ rằng bạn cần một phương pháp danh mục để giúp hợp lý hóa một số mã bạn sẽ thấy bạn sẽ không bao giờ sử dụng lại phương thức đó.

Cũng có những mối nguy hiểm khác, trừ khi bạn đặt tên cho các phương thức danh mục của mình (và ai ngoài ddribin hoàn toàn điên rồ thì sao?) Có khả năng Apple, hoặc một plugin, hoặc một thứ khác chạy trong không gian địa chỉ của bạn cũng sẽ xác định cùng một danh mục phương pháp có cùng tên với một tác dụng phụ hơi khác nhau ....

ĐỒNG Ý. Bây giờ bạn đã được cảnh báo, bỏ qua "không làm phần này". Nhưng tập thể dục cực hạn.


Tôi thích câu trả lời của bạn, lời khuyên của tôi là không nên sử dụng một danh mục để lưu trữ mã tiện ích trừ khi bạn sắp sao chép một số mã ở nhiều nơi và mã rõ ràng thuộc về lớp bạn sắp tham gia ...
Kendall Helmstetter Gelner

Tôi chỉ muốn tham gia và nói lên sự hỗ trợ của tôi cho các phương pháp phân loại không gian tên. Nó chỉ có vẻ như là điều đúng đắn để làm.
Michael Buckley

+1 nếu chỉ cho các chữ số La Mã. Tôi hoàn toàn làm được điều đó!
Brian Postow

14
Counter-point: Trong một năm rưỡi qua, tôi đã tuân theo chính sách ngược lại chính xác: "Nếu nó có thể được thực hiện trong một danh mục, hãy làm như vậy." Kết quả là mã của tôi ngắn gọn hơn, biểu cảm hơn và dễ đọc hơn mã mẫu dài dòng mà Apple cung cấp. Tôi đã mất tổng cộng khoảng 10 phút cho một cuộc xung đột không gian tên và có lẽ tôi đã đạt được nhiều tháng từ hiệu quả mà tôi đã tạo ra cho chính mình. Đối với mỗi người, nhưng tôi đã áp dụng chính sách này khi biết những rủi ro và tôi vô cùng vui mừng vì mình đã làm được.
cduhn

7
Tôi không đồng ý. Nếu nó sẽ là một chức năng và nó áp dụng cho một đối tượng Foundation và bạn có thể nghĩ ra một cái tên hay, hãy gắn nó vào một danh mục. Mã của bạn sẽ dễ đọc hơn. Tôi nghĩ rằng điểm thực sự nổi bật ở đây là: làm mọi thứ trong chừng mực.
mxcl

37

Chống lại phân lớp thế giới. Trong Ca cao rất nhiều được thực hiện thông qua ủy quyền và sử dụng thời gian chạy cơ bản mà trong các khung công tác khác được thực hiện thông qua phân lớp.

Ví dụ, trong Java, bạn sử dụng các thể hiện của các *Listenerlớp con ẩn danh rất nhiều và trong .NET bạn sử dụng các EventArgslớp con của mình rất nhiều. Trong Ca cao, bạn cũng không làm - hành động đích được sử dụng thay thế.


6
Mặt khác được gọi là "Thành phần trên thừa kế".
Andrew Eble

37

Sắp xếp chuỗi theo ý muốn của người dùng

Khi bạn sắp xếp các chuỗi để trình bày cho người dùng, bạn không nên sử dụng compare:phương thức đơn giản . Thay vào đó, bạn nên luôn luôn sử dụng các phương pháp so sánh cục bộ như localizedCompare:hoặc localizedCaseInsensitiveCompare:.

Để biết thêm chi tiết, xem Tìm kiếm, So sánh và Sắp xếp Chuỗi .


31

Thuộc tính khai báo

Thông thường bạn nên sử dụng tính năng Thuộc tính khai báo Objective-C 2.0 cho tất cả các thuộc tính của bạn. Nếu chúng không công khai, hãy thêm chúng trong phần mở rộng lớp. Việc sử dụng các thuộc tính khai báo làm cho ngữ nghĩa quản lý bộ nhớ rõ ràng ngay lập tức và giúp bạn dễ dàng kiểm tra phương thức dealloc của mình hơn - nếu bạn nhóm các khai báo thuộc tính của mình lại với nhau, bạn có thể nhanh chóng quét chúng và so sánh với việc thực hiện phương thức dealloc của bạn.

Bạn nên suy nghĩ kỹ trước khi không đánh dấu các thuộc tính là 'nonatomic'. Như Hướng dẫn ngôn ngữ lập trình mục tiêu C ghi chú, các thuộc tính được mặc định là nguyên tử và chịu chi phí đáng kể. Hơn nữa, chỉ đơn giản là làm cho tất cả các thuộc tính nguyên tử của bạn không làm cho luồng ứng dụng của bạn an toàn. Tất nhiên cũng lưu ý rằng, nếu bạn không chỉ định 'nonatomic' và thực hiện các phương thức truy cập của riêng bạn (thay vì tổng hợp chúng), bạn phải thực hiện chúng theo kiểu nguyên tử.


26

Nghĩ về các giá trị không

Như câu hỏi này lưu ý, các thông báo nilcó giá trị trong Objective-C. Mặc dù điều này thường là một lợi thế - dẫn đến mã sạch hơn và tự nhiên hơn - tính năng đôi khi có thể dẫn đến các lỗi đặc biệt và khó theo dõi nếu bạn nhận được nilgiá trị khi bạn không mong đợi.


Tôi có cái này: #define SXRelease(o); o = nilvà tương tự cho CFReleasefree. Điều này đơn giản hóa mọi thứ.

26

Sử dụng NSAssert và bạn bè. Tôi sử dụng nil làm đối tượng hợp lệ mọi lúc ... đặc biệt là gửi tin nhắn đến nil là hoàn toàn hợp lệ trong Obj-C. Tuy nhiên nếu tôi thực sự muốn chắc chắn về trạng thái của một biến, tôi sử dụng NSAssert và NSParameterAssert, giúp dễ dàng theo dõi các vấn đề.


1
Thêm thông tin ở đây: developer.apple.com/mac/l
Dave Gallagher

23

Đơn giản nhưng quên một. Theo thông số kỹ thuật:

Nói chung, các phương thức trong các lớp khác nhau có cùng bộ chọn (cùng tên) cũng phải chia sẻ cùng loại trả về và loại đối số. Ràng buộc này được áp đặt bởi trình biên dịch để cho phép liên kết động.

trong trường hợp đó, tất cả các bộ chọn có cùng tên, ngay cả trong các lớp khác nhau , sẽ được coi là có các kiểu trả về / đối số giống hệt nhau. Đây là một ví dụ đơn giản.

@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;
}   

đó là một điều dễ quên. Tuy nhiên, quan trọng
Brock Woolf

3
Đây chỉ là một mối quan tâm khi kiềm chế gõ tĩnh. Nếu trình biên dịch biết kiểu, đối số và kiểu trả về có thể khác nhau mà không gặp vấn đề gì. Cá nhân, tôi thấy điều này không thường xuyên là một vấn đề. Apple cũng có rất nhiều phương thức có cùng tên nhưng khác nhau về kiểu trả về. Cuối cùng, có một cờ biên dịch để cảnh báo bạn trong những trường hợp mơ hồ.
Nikolai Ruhe

Nếu chúng ta làm theo hướng dẫn quy ước đặt tên của Apple, tình huống này sẽ không xảy ra :)
Eonil

22

Nếu bạn đang sử dụng Leopard (Mac OS X 10.5) trở lên, bạn có thể sử dụng ứng dụng Dụng cụ để tìm và theo dõi rò rỉ bộ nhớ. Sau khi xây dựng chương trình của bạn trong Xcode, chọn Chạy> Bắt đầu với Công cụ hiệu suất> Rò rỉ.

Ngay cả khi ứng dụng của bạn không hiển thị bất kỳ rò rỉ nào, bạn có thể giữ các vật thể xung quanh quá lâu. Trong Dụng cụ, bạn có thể sử dụng công cụ ObjectAlloc cho việc này. Chọn công cụ ObjectAlloc trong tài liệu Công cụ của bạn và hiển thị chi tiết của công cụ (nếu nó chưa hiển thị) bằng cách chọn Xem> Chi tiết (cần có dấu kiểm bên cạnh). Trong phần "Tuổi thọ phân bổ" trong chi tiết ObjectAlloc, đảm bảo bạn chọn nút radio bên cạnh "Đã tạo và vẫn sống".

Bây giờ, bất cứ khi nào bạn dừng ghi ứng dụng của mình, việc chọn công cụ ObjectAlloc sẽ cho bạn thấy có bao nhiêu tài liệu tham khảo cho mỗi đối tượng còn sống trong ứng dụng của bạn trong cột "# Net". Hãy chắc chắn rằng bạn không chỉ nhìn vào các lớp của riêng bạn, mà cả các lớp của các đối tượng cấp cao nhất của tệp NIB. Ví dụ: nếu bạn không có cửa sổ trên màn hình và bạn thấy các tài liệu tham khảo về một trại giam vẫn còn sống, bạn có thể chưa phát hành nó trong mã của mình.


21

Dọn dẹp trong dealloc.

Đây là một trong những điều dễ quên nhất - đặc biệt. khi mã hóa ở tốc độ 150mph. Luôn luôn, luôn luôn, luôn dọn sạch các thuộc tính / biến thành viên của bạn trong dealloc.

Tôi thích sử dụng các thuộc tính Objc 2 - với ký hiệu dấu chấm mới - vì vậy điều này làm cho việc dọn dẹp không gây đau đớn. Thường đơn giản như:

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

Điều này sẽ chăm sóc của việc phát hành cho bạn và thiết lập các thuộc tính để NULL (mà tôi cân nhắc chương trình phòng thủ - trong trường hợp phương pháp khác tiếp tục xuống trong dealloc truy cập các biến thành viên một lần nữa - hiếm gặp nhưng có thể xảy ra).

Với GC được bật trong 10.5, điều này không còn cần thiết nữa - nhưng bạn vẫn có thể cần phải dọn sạch các tài nguyên khác mà bạn tạo, thay vào đó bạn có thể làm điều đó trong phương pháp hoàn thiện.


12
Nói chung, bạn không nên sử dụng các phương thức truy cập trong dealloc (hoặc init).
mmalc

1
Ngoài lý do hiệu suất (người truy cập chậm hơn một chút so với truy cập trực tiếp) tại sao tôi không nên sử dụng trình truy cập trong dealloc hoặc init?
schwa

1
(a) Lý do hiệu suất hoàn toàn là một lý do trong chính họ (đặc biệt nếu người truy cập của bạn là nguyên tử). (b) Bạn nên tránh mọi tác dụng phụ mà người truy cập có thể có. Điều thứ hai đặc biệt là một vấn đề nếu lớp của bạn có thể được phân lớp.
mmalc

3
Tôi sẽ lưu ý rằng nếu bạn đang chạy trên thời gian chạy hiện đại với các ngà được tổng hợp, bạn phải sử dụng các bộ truy cập trong dealloc. Rất nhiều mã thời gian chạy hiện đại là GC, nhưng không phải tất cả.
Louis Gerbarg

1
Một cái nhìn mở rộng hơn về thời tiết hoặc không sử dụng các phương thức / thuộc tính của người truy cập trong -init-dealloccác phương thức có thể được tìm thấy ở đây: mikeash.com/?page=pyblog/ Kẻ
Johan Kool

17

Tất cả những nhận xét này đều tuyệt vời, nhưng tôi thực sự ngạc nhiên khi không ai đề cập đến Hướng dẫn về Phong cách Mục tiêu-C của Google đã được xuất bản một thời gian trước. Tôi nghĩ rằng họ đã làm một công việc rất kỹ lưỡng.


7
Hmm, ví dụ đầu tiên đã đầy nhảm nhí. Không bao giờ tài liệu thành ngữ ngôn ngữ. Nếu tôi tìm thấy những loại bình luận đó trong một tệp tiêu đề, tôi sẽ không bận tâm đọc tiếp.
Stephan Eggermont

5
Ôi đôi mắt của tôi !!!!! Tôi không thể tin vào những gì tôi thấy.
Eonil


13

Đừng quên rằng NSWindowControll và NSViewControll sẽ phát hành các đối tượng cấp cao nhất của các tệp NIB mà họ quản lý.

Nếu bạn tải thủ công tệp NIB, bạn có trách nhiệm giải phóng các đối tượng cấp cao nhất của NIB khi bạn hoàn thành chúng.


12

Một điều khá rõ ràng cho người mới bắt đầu sử dụng: sử dụng tính năng tự động thụt lề của Xcode cho mã của bạn. Ngay cả khi bạn đang sao chép / dán từ một nguồn khác, một khi bạn đã dán mã, bạn có thể chọn toàn bộ khối mã, nhấp chuột phải vào mã đó, sau đó chọn tùy chọn để thụt lại mọi thứ trong khối đó.

Xcode thực sự sẽ phân tích cú pháp qua phần đó và thụt lề dựa trên dấu ngoặc, vòng lặp, v.v ... Nó hiệu quả hơn nhiều so với việc nhấn phím cách hoặc phím tab cho mỗi dòng.


Bạn thậm chí có thể đặt Tab thành thụt lề và sau đó thực hiện Cmd-A và Tab.
Plumator

10

Tôi biết tôi đã bỏ qua điều này khi lần đầu tiên tham gia vào lập trình Cacao.

Hãy chắc chắn rằng bạn hiểu trách nhiệm quản lý bộ nhớ liên quan đến các tệp NIB. Bạn chịu trách nhiệm phát hành các đối tượng cấp cao nhất trong bất kỳ tệp NIB nào bạn tải. Đọc Tài liệu của Apple về chủ đề này.


6
Đây không phải là sự thật. Việc bạn có chịu trách nhiệm phát hành các đối tượng cấp cao nhất hay không phụ thuộc vào việc bạn kế thừa lớp nào và bạn đang sử dụng nền tảng nào. Xem developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/ trên những người khác.
mmalc

10

Bật tất cả các cảnh báo GCC, sau đó tắt những cảnh báo thường xuyên gây ra bởi các tiêu đề của Apple để giảm tiếng ồn.

Cũng chạy phân tích tĩnh Clang thường xuyên; bạn có thể kích hoạt nó cho tất cả các bản dựng thông qua cài đặt bản dựng "Chạy phân tích tĩnh".

Viết bài kiểm tra đơn vị và chạy chúng với mỗi bản dựng.


Và, nếu bạn có thể, hãy bật Cảnh báo đối xử trên mạng như lỗi Lỗi. Cho phép không có cảnh báo tồn tại.
Peter Hosey

2
Một kịch bản tiện dụng để thiết lập dự án của bạn với các cảnh báo được đề xuất có sẵn tại đây: Rentzsch.tumblr.com/post/237349423/hoseyifyxcodewarnings-scpt
Johan Kool

10

Các biến và thuộc tính

1 / Giữ các tiêu đề của bạn sạch sẽ, ẩn việc thực hiện
Đừng bao gồm các biến thể hiện trong tiêu đề của bạn. Các biến riêng đưa vào lớp tiếp tục như các thuộc tính. Biến công khai khai báo là thuộc tính công khai trong tiêu đề của bạn. Nếu nó chỉ nên được đọc, hãy khai báo nó là chỉ đọc và ghi đè lên nó thành readwrite trong lớp tiếp theo. Về cơ bản tôi không sử dụng biến nào cả, chỉ thuộc tính.

2 / Đặt cho thuộc tính của bạn một tên biến không mặc định, ví dụ:


@synthesize property = property_;

Lý do 1: Bạn sẽ bắt lỗi do quên "bản thân". khi giao tài sản. Lý do 2: Từ các thử nghiệm của tôi, Phân tích rò rỉ trong dụng cụ có vấn đề để phát hiện tài sản bị rò rỉ với tên mặc định.

3 / Không bao giờ sử dụng giữ lại hoặc phát hành trực tiếp trên các thuộc tính (hoặc chỉ trong các tình huống rất đặc biệt). Trong dealloc của bạn chỉ cần gán cho họ một con số không. Giữ lại các thuộc tính có nghĩa là để tự xử lý giữ / phát hành. Bạn không bao giờ biết nếu một setter không, ví dụ, thêm hoặc xóa các quan sát viên. Bạn chỉ nên sử dụng biến trực tiếp bên trong setter và getter của nó.

Lượt xem

1 / Đặt mọi định nghĩa chế độ xem vào xib, nếu bạn có thể (ngoại lệ thường là cài đặt nội dung động và cài đặt lớp). Nó tiết kiệm thời gian (dễ hơn viết mã), dễ dàng thay đổi và giữ cho mã của bạn sạch sẽ.

2 / Đừng cố tối ưu hóa lượt xem bằng cách giảm số lượt xem. Đừng tạo UIImageView trong mã của bạn thay vì xib chỉ vì bạn muốn thêm các lượt xem vào nó. Sử dụng UIImageView làm nền thay thế. Khung nhìn có thể xử lý hàng trăm lượt xem mà không gặp vấn đề gì.

3 / IBOutlets không phải luôn được giữ lại (hoặc mạnh). Lưu ý rằng hầu hết các IBOutlets của bạn là một phần của hệ thống phân cấp chế độ xem của bạn và do đó hoàn toàn được giữ lại.

4 / Phát hành tất cả IBOutlets trong viewDidUnload

5 / Gọi viewDidUnload từ phương thức dealloc của bạn. Nó không được gọi ngầm.

Ký ức

1 / Autorelease object khi bạn tạo chúng. Nhiều lỗi xảy ra do chuyển cuộc gọi phát hành của bạn sang một nhánh if-other hoặc sau câu lệnh return. Phát hành thay vì autorelease chỉ nên được sử dụng trong các tình huống đặc biệt - ví dụ: khi bạn đang chờ đợi một runloop và bạn không muốn đối tượng của mình được tự động phát hành quá sớm.

2 / Ngay cả khi bạn đang sử dụng Đếm tham chiếu tự động, bạn phải hiểu một cách hoàn hảo cách các phương thức phát hành giữ lại hoạt động. Sử dụng phát hành giữ lại thủ công không phức tạp hơn ARC, trong cả hai trường hợp, bạn phải biết về rò rỉ và chu kỳ giữ lại. Xem xét sử dụng phát hành giữ lại thủ công trên các dự án lớn hoặc phân cấp đối tượng phức tạp.

Bình luận

1 / Làm cho mã của bạn tự động được ghi lại. Mỗi tên biến và tên phương thức sẽ cho biết nó đang làm gì. Nếu mã được viết chính xác (bạn cần thực hành nhiều trong phần này), bạn sẽ không cần bất kỳ nhận xét mã nào (không giống như nhận xét tài liệu). Các thuật toán có thể phức tạp nhưng mã phải luôn đơn giản.

2 / Đôi khi, bạn sẽ cần một bình luận. Thông thường để mô tả một hành vi mã không rõ ràng hoặc hack. Nếu bạn cảm thấy mình phải viết bình luận, trước tiên hãy thử viết lại mã để đơn giản hơn và không cần bình luận.

Lõm

1 / Đừng tăng thụt quá nhiều. Hầu hết mã phương thức của bạn nên được thụt vào ở mức phương thức. Các khối lồng nhau (nếu, v.v.) làm giảm khả năng đọc. Nếu bạn có ba khối lồng nhau, bạn nên cố gắng đặt các khối bên trong thành một phương thức riêng biệt. Bốn hoặc nhiều khối lồng nhau không bao giờ nên được sử dụng. Nếu hầu hết mã phương thức của bạn nằm trong if, hãy phủ nhận điều kiện if, ví dụ:


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

return self;

if (!self) {
   return nil;
}

//... long initialization code ...

return self;

Hiểu mã C, chủ yếu là cấu trúc C

Lưu ý rằng Obj-C chỉ là lớp OOP nhẹ trên ngôn ngữ C. Bạn nên hiểu cách các cấu trúc mã cơ bản trong C hoạt động (enums, structs, mảng, con trỏ, v.v.). Thí dụ:


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

giống như:


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

Và nhiều thứ khác nữa

Mantain tài liệu tiêu chuẩn mã hóa của riêng bạn và cập nhật nó thường xuyên. Cố gắng học hỏi từ các lỗi của bạn. Hiểu lý do tại sao một lỗi được tạo ra và cố gắng tránh nó bằng cách sử dụng các tiêu chuẩn mã hóa.

Các tiêu chuẩn mã hóa của chúng tôi hiện có khoảng 20 trang, kết hợp các Tiêu chuẩn mã hóa Java, Tiêu chuẩn Google Obj-C / C ++ và các phần bổ sung của chúng tôi. Tài liệu mã của bạn, sử dụng thụt tiêu chuẩn tiêu chuẩn, khoảng trắng và dòng trống vào đúng nơi, v.v.


9

Có nhiều chức năng hơn .

Objective-C là ngôn ngữ hướng đối tượng, nhưng nhận thức theo kiểu chức năng của khung công tác và được thiết kế theo kiểu chức năng trong nhiều trường hợp.

  1. Có sự tách biệt của tính đột biến. Sử dụng các lớp bất biến làm đối tượng chính và đối tượng có thể thay đổi làm phụ. Chẳng hạn, sử dụng NSArray là chủ yếu và chỉ sử dụng NSMutableArray khi bạn cần.

  2. Có chức năng thuần túy. Không quá nhiều, mua nhiều API khung được thiết kế giống như hàm thuần túy. Nhìn vào các chức năng như CGRectMake()hoặc CGAffineTransformMake(). Rõ ràng hình thức con trỏ trông hiệu quả hơn. Tuy nhiên, đối số gián tiếp với con trỏ không thể cung cấp hiệu ứng phụ. Thiết kế cấu trúc hoàn toàn càng nhiều càng tốt. Riêng các đối tượng nhà nước. Sử dụng -copythay vì -retainkhi truyền một giá trị cho đối tượng khác. Bởi vì trạng thái chia sẻ có thể ảnh hưởng đột biến đến giá trị trong đối tượng khác một cách âm thầm. Vì vậy, không thể có tác dụng phụ. Nếu bạn có một giá trị từ bên ngoài từ đối tượng, sao chép nó. Vì vậy, nó cũng quan trọng thiết kế trạng thái chia sẻ tối thiểu nhất có thể.

Tuy nhiên, đừng sợ sử dụng các chức năng không tinh khiết quá.

  1. Có đánh giá lười biếng. Xem một cái gì đó như -[UIViewController view]tài sản. Khung nhìn sẽ không được tạo khi đối tượng được tạo. Nó sẽ được tạo khi người gọi đọc thuộc viewtính lần đầu tiên. UIImagesẽ không được tải cho đến khi nó thực sự được rút ra. Có rất nhiều thực hiện như thiết kế này. Kiểu thiết kế này rất hữu ích cho việc quản lý tài nguyên, nhưng nếu bạn không biết khái niệm đánh giá lười biếng, thì không dễ để hiểu hành vi của chúng.

  2. Có đóng cửa. Sử dụng khối C càng nhiều càng tốt. Điều này sẽ đơn giản hóa cuộc sống của bạn rất nhiều. Nhưng hãy đọc một lần nữa về quản lý bộ nhớ khối trước khi sử dụng nó.

  3. Có bán tự động. NSAutoreleasePool. Sử dụng -autoreleasechính. Sử dụng -retain/-releasethứ cấp thủ công khi bạn thực sự cần. (ví dụ: tối ưu hóa bộ nhớ, xóa tài nguyên rõ ràng)


2
Đến 3) Tôi sẽ đề xuất cách tiếp cận ngược lại: Sử dụng giữ / phát hành thủ công bất cứ khi nào có thể! Ai biết được mã này sẽ được sử dụng như thế nào - và nếu nó sẽ được sử dụng trong một vòng lặp chặt chẽ, nó có thể làm tăng mức sử dụng bộ nhớ của bạn một cách không cần thiết.
Eiko

@Eiko Đó chỉ là một Tối ưu hóa sớm , không thể là hướng dẫn chung.
Eonil

1
Tôi nghĩ đó là một thứ thiết kế nhiều hơn, đặc biệt là khi làm việc trên các lớp mô hình. Tôi coi việc tăng trí nhớ là một tác dụng phụ và đó không phải là điều tôi muốn xuất hiện thường xuyên. Tồi tệ hơn, một nhà phát triển khác sử dụng mã của tôi không có cơ hội nào ngoài việc bọc các cuộc gọi đắt tiền vào nhóm tự động phát hành (nếu có thể - các đối tượng của tôi có thể được gửi đến một số mã thư viện khác). Và những vấn đề đó rất khó để chẩn đoán sau đó, nhưng giá rẻ để tránh ngay từ đầu. Nếu bạn sao chép / tự động phát hành các đối tượng đã được truyền vào, bạn có thể bị mất nếu chúng lớn hơn bạn mong đợi. Tôi thoải mái hơn với mã GUI, mặc dù.
Eiko

@Eiko Tôi đồng ý autoreleasesẽ giữ bộ nhớ lâu hơn và thủ công retain/releasecó thể giảm mức tiêu thụ bộ nhớ trong trường hợp này. Tuy nhiên, đó phải là hướng dẫn để tối ưu hóa trường hợp đặc biệt (ngay cả khi bạn luôn cảm thấy!), Không thể là lý do để khái quát hóa tối ưu hóa sớm như thực tiễn . Và trên thực tế, đề nghị của bạn không đối nghịch với tôi. Tôi đã đề cập đến nó như một trường hợp thực sự cần thiết :)
Eonil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.