Sử dụng NSString không đổi làm khóa cho NSUserDefaults


86

Tôi đang sử dụng NSUSerDefaults để lưu trữ các tùy chọn của người dùng. Tôi nhớ mình đã đọc ở đâu đó rằng đặt các phím làm hằng số là một ý kiến ​​hay - và tôi đồng ý. Đoạn mã sau là những gì tôi hiện có:

[[NSUserDefaults standardUserDefaults]
        setObject:[NSNumber numberWithInt:polygon.numberOfSides] 
           forKey:@"polygonNumberOfSides"];

Tôi đã thử thay đổi điều này thành:

@implementation Controller

NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides";

-(void)savePolygonInfo {
    [[NSUserDefaults standardUserDefaults]
            setObject:[NSNumber numberWithInt:polygon.numberOfSides] 
               forKey:kPolygonNumberOfSides];
}

Trong khi điều này hoạt động, nó tạo ra " warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type". Tôi muốn giữ cho mã của mình không bị cảnh báo trình biên dịch. Làm cách nào để khắc phục cảnh báo này?

Câu trả lời:


207

Bạn nên sử dụng:

NSString * const kPolygonNumberOfSides = @"..."; // const pointer

thay vì:

NSString const * kPolygonNumberOfSides = @"..."; // pointer to const

Đầu tiên là một con trỏ không đổi đến một đối tượng NSString, trong khi thứ hai là một con trỏ đến một đối tượng NSString không đổi.

Đó là một sự khác biệt tinh tế. Cảnh báo trình biên dịch xảy ra vì setObject:forKey:được khai báo như sau:

- (void)setObject:(id)value forKey:(NSString *)defaultName;

Nó đang mong đợi defaultNameđối số là loại NSString *. Thay vào đó, khi bạn chuyển một con trỏ đến một hằng số, bạn đã tạo cho nó một cái gì đó khác biệt.

Cập nhật: Tôi muốn chỉ ra rằng các hằng số này nên được định nghĩa nhưstaticthể chúng sẽ chỉ được sử dụng từ bên trong một tệp duy nhất. Tôi nói điều này vì bản thân tôi đã gặp phải vấn đề này: nếu bạn không khai báo chúng là tĩnh, thì chúng sẽ tồn tại trong không gian tên chung và bạn sẽ không thể sử dụng một biến có cùng tên trong một tệp khác. xem Hằng số trong Mục tiêu-C để biết thêm thông tin. Để giải thích bằng ví dụ, đây là những gì tôi hiện đang sử dụng cho các khóa mà tôi chỉ cần sử dụng trong một.mtệp:

static NSString * const kSomeLabel = @"...";

1
NSString * const foohoạt động vì NSStringlà bất biến và con trỏ là bất biến nên nó không bao giờ có thể thay đổi đúng không? Ngoài ra, tôi nhớ lại từ C ++ constlà ngầm định static(tối ưu hóa trình biên dịch) nên không cần phải gọi nó ra. Điều đó có đúng ở đây không?
Thứ ba

32

Không sử dụng constvới các đối tượng Objective-C, chúng không thực sự được thiết kế để sử dụng nó. NSStringCác đối tượng (trong số nhiều đối tượng khác) đã mặc định là bất biến theo thiết kế của chúng, vì vậy việc tạo ra chúng constlà vô ích.

Như e.James đã đề xuất , bạn có thể sử dụng an NSString * const, là một con trỏ hằng đến an NSString. Điều này hoàn toàn khác với a const NSString *(tương đương với NSString const *), là một con trỏ đến một hằng số NSString. Sử dụng một NSString * constngăn bạn gán lại kPolyđể trỏ đến một NSStringđối tượng mới .


Điểm tốt về việc sử dụng const. Đó là lý do tại sao rất nhiều lớp Objective-C có các biến thể "Mutable".
e.James

2
Tôi nghĩ điều đó constcũng có nghĩa là bạn không thể chỉ định lại nó. Tôi đoán tôi đã sai.
Dan Rosenstark

18

Để truy cập từ các lớp khác:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey;

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

Chỉ để truy cập bên trong lớp hiện tại:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

5

Tôi sẽ đề nghị thậm chí làm cho hằng số mô tả nhiều hơn. Một hằng số cho số cạnh của một đa giác có thể đến từ bất kỳ đâu. Như một gợi ý, làm thế nào về:

kDefaultsPolygonNumberOfSides;

thay thế.

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.