I used NSURLConnectionobject and called its method cancel sometimes.
Now I should replace NSURLConnection -> NSURLSession. NSURLSession operates with tasks which have cancel method too.
The problem is -[NSURLConnection cancel] just stop the handling of requests but if I use -[NSURLSessionTask cancel] it produces "cancelling error". So how to properly distinguish if cancel is called manually or if a real error is occurred?
I've found 3 solutions:
subclass task/session class
create a custom property via method swizzling in task/session class
the simplest but not very beautiful way - task has string property taskDescription and documentation says that developers are free to use it as they want.
Compare the error code to NSURLErrorCancelled. This error code is generated only when your code cancels the request.
Related
I am creating a class named WeatherService that based on a location will provide the weather forecast (surprise!). There are multiple things that could go wrong here; the location is not found, weather service is not reachable, ...
The service has a method named weatherFor taking a location object as argument. It is asynchronous.
I am using Swift 2. So I have been reading about error handling in Swift 2.0 and there seems to be one way that multiple sources describe and that is a closure with ResultType with a success handler and an error handler. Should I use that? Or should I create a delegate and pass the error like many of the framework objects does such? I already have a delegate for the weather service since I need to know when it starts, when it is done etc.
The delegate protocol has methods like:
Started weather forecast search
Ended weather forecast search
But I don't know if I also should add a method in the delegate that is invoked when something bad happens inside the weather service communicating that an error occured and the weather forecast couldn't be found, or if that is bad? I guess delegates with "error methods" that are invoked isn't bad in Swift?
If you have only one other object interested in receiving notifications about progress, errors etc you can either go with a closure or delegate. It sort of depends on when and where the errors can occur. If you only need to pass on errors or state when making the weatherFor call you can use the closure solution. If errors can happen "anytime", even after - or before - getting the weather, you should use the delegate solution. Or a combination of both.
One other way of doing it is to post notifications when errors occur. This means that more than one object can listen in on updates at the same time.
I have the following code below that loops through an array. I need to check if the finish or fail selector has been called iterating to the next object in my dataArray.
for (id object in dataArray) {
[client setDidFinishSelector:#selector(getDataFinish:)];
[client setDidFailSelector:#selector(getDataFail:)];
[client getData:object];
}
In my getDataFinish method I assign values and I am trying to keep it in order. If I use the above method, the values can get out of order since the client response time can be different for each request..
I see two possible solutions, depending on what you're actually trying to do. It sounds like you're making calls to the internet, so yes you will get varied response time (or no response at all). Because of this, I would recommend using NSNotification. See this answer for more information about that.
Another option is making a flag in your code (AKA a BOOL) that you set to YES when your method has completed. Again, if you're making calls to the web I would not recommend this method as you are setting yourself up for an infinite loop if the user has no service and the BOOL never changes.
If you are still having trouble let me know and I can provide a more detailed answer.
I have simple class for perform network stuff. It's a singleton and it encapsulates NSOperationQueue inside it. When class' user calls some method to getting data from network, this class creates proper instance of operation class inherited from NSOperation sets up it and adds to queue for performing. Obviously, that performing is making asynchronously in separated threads. After getting data from network NSOperation inherited object notifies my network class and it notifies interested delegates about data getting finished or error.
Question is, how can I make unit tests for checking network class' logic? Also, I don't actually want to test server side behavior. I just want to replace actual async call to server with mock and predefined answers to after test handlers' behavior. I want to check how are my classes work, not server side. I understand commonly logic for testing stuff like that but I little bit confused with using OCMock for it.
Best answer will be code example. I'm using OCUnit and OCMock in my project for unit testing.
Also any articles or github links will be perfect.
If all the asynchronous calls go through an internal method in your class, you can simply create a partial mock on your object and use stub/expect on that method. You can then call the public methods as normal and use the mock to verify that the internal method is called. Using the partial mock stops the real implementation from being called, so no network activity should occur.
As to the other half, the call-backs from the asynchronous operation, simply call the method that would be called directly from your tests, then check that your class does the right thing, either by checking its state with OCUnit asserts, or, if it in turn uses callbacks, with another mock.
So I know this is regarding OCMock... but I thought I'd put it out there that I do this successfully with Kiwi and it looks like this.
it(#"should refresh the client's temporary API key if it is stale before sending the request", ^{
ISLDataServiceAdd *addRequest = [ISLDataServiceAdd withRecord:#{ISLFieldContact_FirstName: #"Jason"} table:ISLTableContact];
[[clientMock shouldEventually] receive:#selector(apiKey) andReturn:VALID_API_KEY];
[[clientMock shouldEventually] receive:#selector(hasTemporaryAPIKey) andReturn:theValue(YES)];
[[clientMock shouldEventually] receive:#selector(isTemporaryAPIKeyStale) andReturn:theValue(YES)];
[[clientMock shouldEventually] receive:#selector(refreshTemporaryAPIKeyAndWait:)];
[addRequest sendRequestUsingClient:clientMock completion:nil failure:nil];
});
sendRequestUsingClient:completion:failure: is an asynchronous call, so by using shouldEventually with Kiwi, it knows that it needs to wait some time (default is 1 second) before those selectors will be called.
While using a 3rd party API, I have the requirement to cancel all traffic when a custom response header is set to a certain value. I am trying to find a nice place to do this check only once in my code (and not in every success/failure block, where it works fine). From what I understand, this could be done by overriding -(void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation in my custom AFHTTPClient subclass, but when I implement it like that:
-(void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation
{
NSLog(#"[REQUEST URL]\n%#\n", [operation.request.URL description]);
NSLog(#"[RESPONSE HEADERS]\n%#\n", [[operation.response allHeaderFields] descriptionInStringsFileFormat]);
[super enqueueHTTPRequestOperation:operation];
}
the response headers are nil. Can anybody help me with that?
At the moment when operations are being created and enqueued in AFHTTPClient, they will not have the response from the server--that will be assigned when the request operation is actually executed.
Although the requirement to cancel all traffic seems unorthodox (at least if outside of the conventions of HTTP), this is easy to accomplish:
In your AFHTTPClient subclass, add a BOOL property that stores if requests should be prevented, and then used in enqueueHTTPRequestOperation. Then, override HTTPRequestOperationWithRequest:success:failure: to execute the specified success block along with some logic to set the aforementioned property if the salient response is present.
Is it like if I "pass a message" between two objects and if they happened to be have been instantiated in different threads then the invoked method would still run in its object's thread?
Calling a method is resolved at compile time and the method can be expected to be present at run time. Message passing is resolved at run time and the receiver object does not need to understand how to handle the message.
The term "message passing" in Objective-C does not have anything to do with threading.
I found a good article about this topic here: http://iskren.info/reading/info/ObjC/reading/dynamite.html