The last two are identical; "atomic" is the default behavior (note that it is not actually a keyword; it is specified only by the absence of nonatomic
-- atomic
was added as a keyword in recent versions of llvm/clang).
Assuming that you are @synthesizing the method implementations, atomic vs. non-atomic changes the generated code. If you are writing your own setter/getters, atomic/nonatomic/retain/assign/copy are merely advisory. (Note: @synthesize is now the default behavior in recent versions of LLVM. There is also no need to declare instance variables; they will be synthesized automatically, too, and will have an _
prepended to their name to prevent accidental direct access).
With "atomic", the synthesized setter/getter will ensure that a whole value is always returned from the getter or set by the setter, regardless of setter activity on any other thread. That is, if thread A is in the middle of the getter while thread B calls the setter, an actual viable value -- an autoreleased object, most likely -- will be returned to the caller in A.
In nonatomic
, no such guarantees are made. Thus, nonatomic
is considerably faster than "atomic".
What "atomic" does not do is make any guarantees about thread safety. If thread A is calling the getter simultaneously with thread B and C calling the setter with different values, thread A may get any one of the three values returned -- the one prior to any setters being called or either of the values passed into the setters in B and C. Likewise, the object may end up with the value from B or C, no way to tell.
Ensuring data integrity -- one of the primary challenges of multi-threaded programming -- is achieved by other means.
Adding to this:
atomicity
of a single property also cannot guarantee thread safety when multiple dependent properties are in play.
Consider:
@property(atomic, copy) NSString *firstName;
@property(atomic, copy) NSString *lastName;
@property(readonly, atomic, copy) NSString *fullName;
In this case, thread A could be renaming the object by calling setFirstName:
and then calling setLastName:
. In the meantime, thread B may call fullName
in between thread A's two calls and will receive the new first name coupled with the old last name.
To address this, you need a transactional model. I.e. some other kind of synchronization and/or exclusion that allows one to exclude access to fullName
while the dependent properties are being updated.
The problem comes from webkit which blocks the response because of cross domain origin request. Since we mock the response we have to force the Access-Control-Allow-Origin.
Then we also need to force the content-type of the response.
Here is where the magic happens :
NSDictionary *headers = @{@"Access-Control-Allow-Origin" : @"*", @"Access-Control-Allow-Headers" : @"Content-Type"};
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"1.1" headerFields:headers];
The final implementation of the protocol :
#import "EpubProtocol.h"
@implementation EpubProtocol
#pragma mark - NSURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
BOOL isAwsRequest = [self request:request contains:@"s3.amazonaws.com"];
return isAwsRequest;
}
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest
{
return theRequest;
}
- (void)startLoading {
NSURLRequest *request = [self request];
//Mock Amazon call
if([EpubProtocol request:request contains:@"s3.amazonaws.com"]) {
NSString *path = [[NSBundle bundleForClass:self.class] pathForResource:@"epub1" ofType:@"json"];
NSData *data = [NSData dataWithContentsOfFile:path];
[self mockRequest:request data:data];
}
}
- (void)stopLoading
{
NSLog(@"Did stop loading");
}
#pragma mark - Request utils
+ (BOOL) request:(NSURLRequest*)request contains:(NSString*)domain {
NSString *str = [[request URL] absoluteString];
NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", domain];
return [pred evaluateWithObject:str];
}
#pragma mark - Mock responses
-(void) mockRequest:(NSURLRequest*)request data:(NSData*)data {
id client = [self client];
NSDictionary *headers = @{@"Access-Control-Allow-Origin" : @"*", @"Access-Control-Allow-Headers" : @"Content-Type"};
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"1.1" headerFields:headers];
[client URLProtocol:self didReceiveResponse:response
cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[client URLProtocol:self didLoadData:data];
[client URLProtocolDidFinishLoading:self];
}
@end
Nothing special in the JS :
function loadJSONDoc()
{
var url = "https://s3.amazonaws.com/youboox_recette/epub.json";
$.ajax({
url: url,
dataType: 'json',
contentType: "application/json",
success: function(jsonData){
alert('success');
document.getElementById("myDiv").innerHTML='<p>'+$.param(jsonData)+'</p>';
},
error: function (request, status, error) {
alert("failure :" + request.status );
}
});
}
Best Answer
Updated answer for iOS 11 and macOS 10.13
Since iOS 11 it is possible to declare an object that conforms to the
WKURLSchemeHandler
protocol and register it in theWKWebView
configuration:-[WKWebViewConfiguration setURLSchemeHandler:forURLScheme:]
.Old answer
WKWebView
makes requests and renders content out-of-process, meaning your app does not hear the requests they make. If you are missing a functionality, now is the time to open a bug report and/or an enhancement request with Apple.As of iOS 10.3 SDK,
WKWebView
is still unable to make use of customNSURLProtocol
s using public APIs.Enterprising developers have found an interesting method:
+[WKBrowsingContextController registerSchemeForCustomProtocol:]
It supposedly adds the provided scheme to a list of custom protocol handled schemes and should then work withNSURLProtocol
.