Viblo CTF
+1

Cách tối ưu để định nghĩa 1 string constant trong Objective-C

Mở đầu

Khi phát triển một dự án iOS nói chung, chúng ta cần định nghĩa các string constant để có thể sử dụng lại và tránh việc hardcode không cần thiết. Vậy đâu là "the best way" để làm việc này? Thông thường nhưng iOS Dev để nhanh gọn hay sử dụng macro để định nghĩa một string constant. Cú pháp như sau:

#define k_InvalidEmailMessage = @"Your email is invalid.";

Về cơ bản cách này không vấn đề gì, thậm chí có thể được dùng rất phổ biến trong phần nhiều các dự án. Đây là lý do:

  1. Dùng #define cho mục đích code dễ đọc và dễ sửa đổi về sau này, khi muốn thay đổi giá trị hoặc tên keyword, chúng ta chỉ cần thay đổi tại chỗ đã define, việc này không gây ra sai sót khi find/replace thiếu.
  2. Khi compile thì pre-processor sẽ replace tất cả defile name(keyword tương ứng "k_InvalidEmailMessage") với các giá trị sau nó, việc này không mất quá nhiều thời gian compile.

Tuy nhiên, bên cạnh những ưu điểm đó thì còn tồn tại một số nhược điểm dẫn đến việc không khuyến khích sử dụng macro trong việc định nghĩa string constant. Đây là lý do:

  1. Macros không phải là một kiểu dữ liệu xác định.
  2. Khi sử dụng debgger command, nếu k_InvalidEmailMessage là macro, thì debugger sẽ không hiểu được.
  3. Khi muốn sử dụng compare 2 string, việc sử dụng 1 kiểu xác định (NSString) sẽ giúp việc compare 2 con trỏ trở lên dễ dàng và tốc độ nhanh hơn so với sử dụng macro
// Constants.h
FOUNDATION_EXPORT NSString *const MyFirstConstant;
FOUNDATION_EXPORT NSString *const MySecondConstant;
// Constants.m
NSString *const MyFirstConstant = @"FirstConstant";
NSString *const MySecondConstant = @"SecondConstant";

Sử dụng stringInstance == MyFirstConstant nhanh hơn [stringInstance isEqualToString:MyFirstConstant] 4. Không thể define 1 kiểu dữ liệu cụ thể với macro

#define MY_INT_CONSTANT ((int) 12345)

Vậy có thể dùng các cách khác được không?

1. Enum

Câu trả lời là không, vì sao? Trong Objective-C, kiểu enum chỉ dùng để định nghĩa các biến hằng kiểu Integer, chúng ta có thể sử dụng NS_ENUM and NS_OPTIONS macros.

2. App-Prefix.pch

Có thể không vấn đề gì nhưng không nên, vì các biến constant chỉ được sử dụng ở một số class trong project, việc đưa toàn bộ constant vào App-Prefix.pch là thừa thãi và không khuyến khích sử dụng.

3. const

Tốt nếu là local constant, nhưng để sử dụng ở những chỗ khác(các class khác thì không thể)

4. static const

Tốt nếu là constant của một số file xác định hay class xác định

5. extern const

Đây có lẽ là cách tốt nhất và cũng được khuyến khích sử dụng. Chúng ta tạo ra 2 file .h, .m. File header để khai báo biến constant:

//.h
extern NSString *const InvalidEmailMessage;
//.m
NSString *const InvalidEmailMessage = @"Your email is invalid.";

Như vậy khi sử dụng ở class nào đó chúng ta chỉ việc import header file và gọi biến constant theo name ra dùng.

6. FOUNDATION_EXPORT

Còn 1 cách khác cũng được khuyến khích là sử dụng từ khóa FOUNDATION_EXPORT vì đây là define của Objective-C thay vì extern của C/C++, về bản chất FOUNDATION_EXPORT chỉ là porter của extern - nghĩa là khi compile time, IDE sẽ transfer FOUNDATION_EXPORT thành extern.

.h

FOUNDATION_EXPORT NSString * const InvalidEmailMessage;
.m

NSString * const InvalidEmailMessage = @"Your email is invalid.";

Summary

Tóm lại, việc định nghĩa 1 string constant có nhiều cách, mỗi cách đều có những ưu/nhược điểm riêng. Tuy nhiên việc đi theo một convention chung sẽ giúp cho các dự án, các member trong từng dự án thống nhất và dễ maintain hơn.

  • Khuyến khích:
    1. extern const
    2. FOUNDATION_EXPORT
  • Không khuyến khích:
    1. #define
    2. enum
    3. App-Prefix.pch

All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.