NSURL - 没有可变子类,因此属性不需要“copy”吗?

10
@interface SomeClass : NSObject

@property (copy,   nonatomic) NSString *usefulString;
@property (strong, nonatomic) NSString *dangerousString;

@property (copy,   nonatomic) NSURL *curiousURLOne;
@property (strong, nonatomic) NSURL *curiousURLTwo;

@end
在上述类中,dangerousString 被认为是一个不好的想法,因为 NSMutableString 继承自 NSString。这意味着您的类的用户可能会将一个可变字符串设置为 dangerousString,然后在实例化 SomeClass 的过程中更改可变字符串的值,从而使得该实例面临危险。属性 usefulString 不具有此风险,因为它将值复制到一个新的(不可变)字符串对象中。
但是,对于 NSURL(以及任何其他没有可变对应项的基础类,例如 NSNumber),属性声明的复制语义似乎是不必要的。NSURL 符合 NSCopying 的 copyWithZone:(……但我不禁想知道它是否只返回具有增加的保留计数的相同对象——为什么还要做其他事情?)
为什么会把没有被修改的属性声明为 copy 呢?
2个回答

9

iOS7中可以使用NSURLComponents,现在它变得非常简单,看看这个例子:

NSString *urlString = @"https://mail.google.com/mail/u/0/?shva=1#inbox";
NSURLComponents *components = [[NSURLComponents alloc] initWithString:urlString];

NSLog(@"%@ - %@ - %@ - %@", components.scheme, components.host, components.query, components.fragment);



NSURLComponents *components = [NSURLComponents new];
[components setScheme:@"https"];
[components setHost:@"mail.google.com"];
[components setQuery:@"shva=1"];
[components setFragment:@"inbox"];
[components setPath:@"/mail/u/0/"];

[webview loadRequest:[[NSURLRequest alloc] initWithURL:[components URL]]];

我不确定这与上述问题有什么关系?看起来你只是在展示如何使用NSURLComponents创建一个URL。 - codecaffeine
是的,但问题并不是在问如何更改URL的一部分,而是在问是否需要将NSURL属性设置为“copy”,因为它是不可变的。 - codecaffeine

6

苹果不提供可变的子类,并不意味着恶意用户不能构建一个特定的可变子类来欺骗你的类。如果你假设字符串可以在你的类背后被改变,那么你至少需要考虑到一个有恶意的用户将NSURL扩展为可变类的可能性:

@interface TrickThemURL : NSURL
    // override key properties, such as baseURL and host, to be mutable
@end

如果一个程序员给你一个 TrickThemURL 对象,而你在验证之前没有复制它,那么这个程序员现在可以自由地更改 URL,而不让你的类知道。

3
如果 TrickThemURL 恶意的话,它难道不会直接覆盖 -copy 吗? - Darren
@Darren 我想你是对的 - 一个保险的方法是使用 [NSURL urlWithString:urlArg.standardizedURL] 然后验证结果。 - Sergey Kalinichenko
根据这次讨论,似乎 strong 是“安全的”。这留下了一个猫捉老鼠的机会,但在这个类的实用性超越单个应用程序的范围之前,这可能是可以接受的。 - edelaney05
1
@edelaney05 这真的取决于您计划部署库的环境的敌意程度。如果存在财务激励让用户入侵您的库(例如,通过让他们欺骗使用不受信任的攻击服务器来最终导致您支付更多的费用),则应在自定义setURL方法中自己复制URL,并在复制后检查其不可变结果。当潜在黑客攻击的后果较轻时,可以使用strong - Sergey Kalinichenko
1
但即使没有敌意,一个没有经验或者只是一个复杂的 bug 的用户在更改 setter 使用的值(而不使用子类化)时,仍然可以更改已设置的属性。@dasblinkenlight 甚至有些恶意用户可能会直接覆盖 urlWithString:urlArg.standardizedURL ;) - Binarian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接