使用常量 NSString 作为 NSUserDefaults 的键

Posted

技术标签:

【中文标题】使用常量 NSString 作为 NSUserDefaults 的键【英文标题】:Using a constant NSString as the key for NSUserDefaults 【发布时间】:2010-10-19 17:15:58 【问题描述】:

我正在使用 NSUSerDefaults 来存储用户首选项。我记得在某处读到将键设置为常量是一个好主意——我同意。以下代码是我目前拥有的:

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

我尝试将其更改为:

@implementation Controller

NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides";

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

虽然这确实有效,但它会产生“warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type”。我热衷于让我的代码免受编译器警告的影响。如何解决此警告?

【问题讨论】:

【参考方案1】:

对于其他类的访问:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey;

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

仅在当前类内访问:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

【讨论】:

【参考方案2】:

你应该使用:

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

代替:

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

第一个是指向 NSString 对象的常量指针,而第二个是指向常量 NSString 对象的指针。

这是一个微妙的区别。发生编译器警告是因为 setObject:forKey: 声明如下:

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

预计defaultName 参数的类型为NSString *。当你传入一个指向常量的指针时,你给了它一些不同的东西。

更新:我想指出,如果这些常量仅用于单个文件中,则应将它们定义为 static。我这样说是因为我自己也遇到过这个问题:如果你不将它们声明为静态,那么它们将存在于全局命名空间中,你将无法在另一个文件中使用同名的变量。请参阅Constants in Objective-C 了解更多信息。举例说明,这是我目前只需要在一个 .m 文件中使用的密钥:

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

【讨论】:

NSString * const foo 之所以有效,是因为NSString 是不可变的,并且指针是不可变的,所以它永远不会改变对吗?另外,我从 C++ 中回忆起 const 隐含为 static (编译器优化),因此无需调用它。这里也是这样吗?【参考方案3】:

不要将const 与Objective-C 对象一起使用,它们并不是真正设计用于使用它的。 NSString 对象(以及许多其他对象)在设计上已经默认是不可变的,因此将它们设置为 const 是没有用的。

作为e.James suggested,您可以使用NSString * const,它是一个指向NSString 的常量指针。这与const NSString *(相当于NSString const *)略有不同,后者是一个指向常量NSString 的指针。使用 NSString * const 可以防止您重新分配 kPoly 以指向新的 NSString 对象。

【讨论】:

关于使用 const 的好处。这就是为什么很多 Objective-C 类都有“可变”变体的原因。 我认为const 也意味着你不能重新分配它。我想我错了。 鉴于你的第二段,我认为你应该修改你的第一段。无法重新分配标识符是一种有效的用途,并且与对象本身的可变性没有任何关系。如果您将 NSString 声明为 NSString* const foo = @"bar",然后尝试重新分配它,您将收到错误 Cannot assign to variable 'foo'...,这正是我在声明 const 时所希望的。【参考方案4】:

我建议甚至使常数更具描述性。多边形边数的常数可以来自任何地方。作为一个建议,如何:

kDefaultsPolygonNumberOfSides;

改为。

【讨论】:

以上是关于使用常量 NSString 作为 NSUserDefaults 的键的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C JSON 到 TableView 非常慢

NSString基本概念

使用 reverseGeocodeLocation 将用户的状态作为 NSString 返回

使用带有 NSString 的 XCTAssertEqual 作为错误消息参数

使用 NSString 作为超链接

NSString 和 UITapGestureRecognizer 作为方法参数