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

In the above class, dangerousString is considered a bad idea because NSMutableString inherits from NSString. Meaning it is possible a user of your class could set a mutable string to dangerousString, and then later change the value of the mutable string out from underneath the instance of SomeClass. The property usefulString doesn't have this danger as it copies the value into a new (immutable) string object.

However, it seems like for NSURL (and any other foundation classes that don't have mutable counterparts - e.g. NSNumber) the copy semantic of the property declaration is unnecessary. NSURL does conform to NSCopying's copyWithZone: (...but I have to wonder if it doesn't just return the same object with an increased retain count - why would it do anything else?)

Why would you declare properties as copy that don't have a danger of being mutated?

edelaney05
  • 6,822
  • 6
  • 41
  • 65

2 Answers2

9

With iOS7 you can use NSURLComponents, now it's very simple, look this examples:

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]]];
Salmo
  • 1,788
  • 1
  • 18
  • 29
  • I’m unsure what this has to do with the above question? It looks like you’re just showing how t create a URL using NSURLComponents. – codecaffeine Jul 28 '15 at 01:16
  • Yes, but the question wasn’t asking how to change a portion of the URL, it was asking if it’s necessary to set an `NSURL` property as `copy` because it’s immutable. – codecaffeine Jul 28 '15 at 14:45
6

The fact that Apple does not supply a mutable subclass does not mean that a malicious user could not build one specifically to trick your class. If you operate under the assumption that strings can be changed behind your class's back, you need to at least allow for a possibility of an ill-intentioned user extending NSURL into a mutable class:

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

If a programmer gives you an object of TrickThemURL and you fail to copy it before the validation, that programmer is now free to change the URL without letting your class know.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 3
    Wouldn't TrickThemURL just override -copy if it wanted to be malicious? – Darren Dec 21 '12 at 03:05
  • @Darren I guess you're right - a way to be safe is to use `[NSURL urlWithString:urlArg.standardizedURL]` and then validate the result. – Sergey Kalinichenko Dec 21 '12 at 03:10
  • Based on this discussion it seems that `strong` is "safe." This leaves open an opportunity for a cat-and-mouse game, but that may be okay until this class's usefulness grows beyond the bounds of a single application. – edelaney05 Dec 21 '12 at 17:03
  • 1
    @edelaney05 It really depends on the level of hostility of the environment in which you plan to deploy your library. If there is a financial incentive for users to hack your library (e.g. by letting them spoof something using an untrusted attack server that ultimately leads to you paying them more money) then you should make a copy of the URL yourself in a custom `setURL` method, and check its immutable result after the copy. When consequences of potential hacking is less severe, you could use `strong` instead. – Sergey Kalinichenko Dec 21 '12 at 17:10
  • 1
    But even without hostility, a user without experience or simply a complex bug could change the property after it has been set, when changing the value used for the setter (without using subclassing). @dasblinkenlight hostile users could even just override urlWithString:urlArg.standardizedURL ;) – Binarian Aug 31 '13 at 09:40