📜 ⬆️ ⬇️

Understanding NSURL / NSURLComponents

From the translator: In the light of recent events, being a developer on Objective-S has become not so fashionable, some are already running to take it to the scrap, but I think that it is still too early to do so, therefore I allow myself to share the translation. Starting to read the original, I did not expect anything new in a seemingly simple and obvious topic, but in the end I made quite useful points.


There are, let's call them “one-dimensional”, data types: numbers, strings, containing essentially several values ​​that can be extracted using mathematical operations or simple parsing. An example is the hexadecimal notation of color # EE8262 , which contains components for red, blue, and green, or, for example, a regular expression, which, with the help of a pair of characters, allows you to search for complex substrings.

Among all "one-dimensional" data types, the undisputed winner is the URI . Judge for yourself, here in one human-readable line there is enough data to understand where this or that information is located, which was, is, or will ever be on the computer.
')
Typically, a URI includes the following components: a schema, some hierarchical part, a query, and a fragment:
  : [ ? ] [ # ] 

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];
: [ ? ] [ # ]

, HTTP , , , :
foo:// username: password @ example.com :8042 /over/there/index .dtb ?type=animal&name=narwhal #nose scheme username password hostname port path extension query fragment
URL . URI .

Foundation URL' NSURL .

NSURL URLWithString :
NSURL *url = [NSURL URLWithString:@"http://example.com"];

If the string we give is not a valid URL , we get nil .

NSString has a certain rudimentary functionality for manipulating paths, you can read about it here (including, among other things, what Apple advises to move from NSString to the NSURL-like API for such classes as NSFileManager ). Unfortunately, the migration from NSString to NSURL does not go as smoothly as we would like. Despite the fact that converting from NSString to NSURL is not the most convenient step, this is correct. If the value is a URL , it should be stored and transmitted as NSURL ; using a class other than its intended purpose is a sign of laziness and an example of poor API design.

By the way, what do you think about using @@ as a literal for NSURL (i.e. @@ "http://example.com")?

NSURL also has a class method + URLWithString: relativeToURL:, which is used to create a URL from a string relative to some base URL. The behavior of this method may not always be obvious when the relative path ends in `/`

Here are some examples that show how this method works:

 NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"]; [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/ [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/ 


URL Components


NSURL provides methods for accessing all URL components described in RFC 2396 :


Documentation and examples can be found in the documentation - this is a good way to get acquainted with all the components.

Separately, it must be said that although the username and password can be stored in the URL , it is better to use NSURLCreditnal or store them in a keychain.


NSURLComponents


NSURLComponents appeared in iOS 7 and Mac OS 10.9, to be honest, NSMutableURL would be the best name for this class. Due to the lack of documentation, this class has become one of the most "secret" additions to the Foundation .

NSURLComponents instances are created using :( + componentsWithString: and + componentsWithURL: resolvingAgainstBaseURL:) . Of course, you can just send alloc and init , without any arguments, to create an empty container.

The difference between NSURL and NSURLComponents is that the latter property has mutable properties. It provides a safe and easy way to change individual components in a URL :

Attempting to set the wrong scheme or select a negative number for the port will result in an exception.

NSURLComponents also have variable percent-encoded options for each component.

Upon receipt of these properties, we get them in the percent-encoded form. Changing these properties you need to give the already enveloped line, otherwise - the exception. `;` - is a valid character, but it is also recommended to encode it for better compatibility with NSURL . ( -stringByAddingPercentEncodingWithAllowedCharacters: zankodit all `;` if you pass the URLPathAllowedCharacterSet )


Percent-Encoding


NSURL - toll-free bridged for CFURLRef . The latter is a low-level C API that efficiently replicates the NSURL functionality, but with the exception of CFURLCreateStringByAddingPercentEscapes and CFURLCreateStringByReplacingPercentEscapesUsingEncoding :

- CFURLCreateStringByAddingPercentEscapes: creates a copy of the string, replacing specific characters with the corresponding zapped text in the appropriate encoding.
 CFStringRef CFURLCreateStringByAddingPercentEscapes ( CFAllocatorRef allocator, CFStringRef originalString, CFStringRef charactersToLeaveUnescaped, CFStringRef legalURLCharactersToBeEscaped, CFStringEncoding encoding ); 


- CFURLCreateStringByReplacingPercentEscapesUsingEncoding: does the opposite and replaces backscored sequences with corresponding characters.

 CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding ( CFAllocatorRef allocator, CFStringRef origString, CFStringRef charsToLeaveEscaped, CFStringEncoding encoding ); 


URL for bookmarks


The last question I would like to discuss is the URLs for the bookmarks, these are the ways you can use to safely link files between application launches. You can think of them as file descriptors .

A bookmark is a closed file structure, which is enclosed in an NSData object; it describes the location of the file. While the path and reference URL are potentially unreliable, a bookmark can be used to recreate the URL , even if the file has been moved or renamed.


More about the links can be found in the "Locating Files Using Bookmarks" from the apple documentation.

Source: https://habr.com/ru/post/225969/


All Articles