2010-01-19 36 views
44

Tôi là một chút nhầm lẫn như khi nó tốt nhất để sử dụng:Khi sử dụng static string vs #define

static NSString *AppQuitGracefullyKey = @"AppQuitGracefully"; 

thay vì

#define AppQuitGracefullyKey @"AppQuitGracefully" 

Tôi đã nhìn thấy những câu hỏi như thế này cho C hoặc C++, và tôi nghĩ điều khác biệt ở đây là điều này dành riêng cho Objective C, sử dụng một đối tượng, và trên một thiết bị như iPhone, có thể có stack, không gian mã hoặc các vấn đề bộ nhớ mà tôi chưa nắm bắt.

Một sử dụng sẽ là:

appQuitGracefully = [[NSUserDefaults standardUserDefaults] integerForKey: AppQuitGracefullyKey]; 

Hoặc nó chỉ là một vấn đề của phong cách?

Cảm ơn.

Trả lời

58

Nếu bạn sử dụng tĩnh, trình biên dịch sẽ nhúng chính xác một bản sao của chuỗi trong tệp nhị phân của bạn và chỉ chuyển con trỏ tới chuỗi đó, dẫn đến các tệp nhị phân nhỏ gọn hơn. Nếu bạn sử dụng #define, sẽ có một bản sao riêng biệt của chuỗi được lưu trữ trong nguồn trên mỗi lần sử dụng. Chuỗi liên tục coalescing sẽ xử lý nhiều người trong số các dups nhưng bạn đang làm cho mối liên kết làm việc chăm chỉ hơn không có lý do.

+9

Liên tục chuỗi liên kết là công việc của trình biên dịch chứ không phải trình liên kết. – kennytm

+1

Điều này không đúng. Objective-c sử dụng [String Interning] (https://en.wikipedia.org/wiki/String_interning) như được mô tả [ở đây] (http://nshipster.com/equality/). '# define' không _not_ lưu một bản sao của chuỗi cho mỗi lần sử dụng. Và @kennytm là đúng, trình biên dịch thực hiện điều đó, không phải là mối liên kết –

+1

@ AndréFratelli Trong thực tế, chuỗi liên kết coalescing là một tối ưu hóa liên kết, và nó được thực hiện bởi liên kết tĩnh trong OS X/macOS cho cả C và CF/NSStrings . Nó không được thực hiện bằng cách sử dụng chuỗi interning, và nó không được thực hiện bởi trình biên dịch (mặc dù trình biên dịch có thể coalesce strings chính nó trước khi viết ra các tập tin đối tượng tạo ra nó). Bạn có thể thấy mã thực hiện điều này trong [nguồn liên kết] (http://opensource.apple.com/source/ld64/ld64-264.3.102/). Cho nên không, kennytm không đúng; nó thực sự là mối liên kết. – alastair

3

Tôi sử dụng static khi tôi cần xuất các ký hiệu NSString từ thư viện hoặc khung. Tôi sử dụng #define khi tôi cần một chuỗi ở nhiều nơi mà tôi có thể thay đổi dễ dàng. Dù sao, trình biên dịch và trình liên kết sẽ chăm sóc tối ưu hóa.

14

Xem "static const" vs "#define" vs "enum". Ưu điểm chính của static là loại an toàn.

Ngoài ra, cách tiếp cận #define giới thiệu tính linh hoạt của nối chuỗi nội tuyến không thể thực hiện được với các biến tĩnh, ví dụ:

#define ROOT_PATH @"/System/Library/Frameworks" 
[[NSBundle bundleWithPath:[email protected]"/UIKit.framework"] load]; 

nhưng điều này có lẽ không phải là một phong cách tốt :).

+33

Tôi rất ngạc nhiên. Tôi không có ý tưởng '@" một chuỗi "@" một chuỗi khác "' là hợp lệ. –

+0

Từ bình luận của bạn cho câu trả lời của cdespinosa, có nghĩa là sử dụng #define sẽ không tạo ra sự trùng lặp? – user523234

+0

@ user523234. Trình biên dịch sử dụng [String Interning] (https://en.wikipedia.org/wiki/String_interning) –

4

Sau khi thực hiện một số tìm kiếm (this câu hỏi/trả lời trong số những thứ khác) Tôi nghĩ điều quan trọng là phải nói rằng bất cứ lúc nào khi bạn đang sử dụng chuỗi ký tự liên tục. đối tượng cùng một đối tượng.

Vì vậy, tôi nghĩ (và tôi xin lỗi cho tôi nếu tôi sai) rằng câu này trong câu trả lời ở trên là sai: If you use a #define, there will be a separate copy of the string stored in the source on each use.

3

SỬ DỤNG #define:

bạn không thể gỡ lỗi các giá trị của Mã định danh

làm việc với #define và các macro khác là công việc của Pre-Processor, Khi bạn nhấn Build/Run trước, nó sẽ xử lý trước mã nguồn, nó sẽ hoạt động với tất cả các macro (bắt đầu với ký hiệu #),

Giả sử, bạn đã tạo ra,

#define LanguageTypeEnglish @"en" 

và sử dụng này tại 2 nơi trong mã của bạn.

NSString *language = LanguageTypeEnglish; 
NSString *languageCode = LanguageTypeEnglish; 

nó sẽ thay thế "LanguageTypeEnglish" với @"en", ở tất cả các nơi. Vì vậy, 2 bản sao của @"en" sẽ được tạo. ví dụ:

NSString *language = @"en"; 
NSString *languageCode = @"en"; 

Hãy nhớ rằng, cho đến khi quá trình này, trình biên dịch không có trong hình.

Sau khi tiền xử lý tất cả các macro, biên dịch đi kèm trong hình ảnh, và nó sẽ nhận được mã đầu vào như thế này,

NSString *language = @"en"; 
NSString *languageCode = @"en"; 

và biên dịch nó.

SỬ DỤNG tĩnh:

nó tôn trọng phạm vi và là loại an toàn. bạn có thể gỡ lỗi giá trị định danh

Trong quá trình biên soạn, nếu trình biên dịch tìm thấy,

static NSString *LanguageTypeRussian = @"ru"; 

sau đó nó sẽ kiểm tra xem biến có cùng tên được lưu trữ trước đó, nếu có, nó sẽ chỉ vượt qua con trỏ của biến đó, nếu không, nó sẽ tạo biến đó và chuyển con trỏ của nó, lần sau trở đi nó sẽ chỉ truyền con trỏ của cùng một biến.

Vì vậy, sử dụng tĩnh, chỉ một bản sao của biến được tạo trong phạm vi.

4

Tôi thực sự khuyên bạn không nên sử dụng extern. Objective-C đã định nghĩa FOUNDATION_EXPORT đó là more portable hơn extern, do đó, một NSString dụ toàn cầu sẽ giống như thế này:

.h

FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey; 

.m

NSString * const AppQuitGracefullyKey = @"AppQuitGracefully"; 

Tôi thường đặt những trong các tệp kê khai (chẳng hạn như MyProjectDecl.h) và nhập bất cứ khi nào tôi cần.

Có một vài sự khác biệt đối với các phương pháp:

  • #define có một số nhược điểm, chẳng hạn như không được an toàn loại. Đúng là có cách giải quyết cho điều đó (chẳng hạn như #define ((int)1)) nhưng điểm là gì? Và bên cạnh đó, có những nhược điểm về cách tiếp cận đó. Trình biên dịch thích hằng số. Xem phần this thảo luận.
  • tĩnh globals là visible in the file they are declared.
  • extern làm cho biến có thể nhìn thấy tất cả các file. Điều đó tương phản với tĩnh.

Tĩnh và bên ngoài khác nhau về khả năng hiển thị.Nó cũng đáng chú ý là không phải của các phương pháp tiếp cận này trùng lặp chuỗi (thậm chí không #define) như trình biên dịch sử dụng String Interning để ngăn chặn điều đó. Trong this NSHipster post họ xuất trình giấy tờ:

NSString *a = @"Hello"; 
NSString *b = @"Hello"; 
BOOL wtf = (a == b); // YES 

Nhà điều hành == lợi nhuận YES chỉ khi hai biến trỏ vào cùng một ví dụ. Và như bạn có thể thấy, nó có.

Kết luận là: sử dụng FOUNDATION_EXPORT cho các hằng số chung. Đó là gỡ lỗi thân thiện và sẽ được hiển thị allover dự án của bạn.

Các vấn đề liên quan