Restkit POST ManagedObjectRequestOperation or ObjectRequestOperation? - ios

My application sends a POST request to a server with some parameters, and the server responds with an array of objects. I've been using RKObjectManager's managedObjectRequestOperationWithRequest:managedObjectContext:success:failure: function to do this, but after having some issues with a mysterious intermittent crash that I suspect is related to the underlying restkit code (RestKit Core Data NSError dealloc Crash) I recently did another read through of the docs and came across RKObjectManager's postObject:path:parameters:success:failure function.
Substituting this in place of the managedObjectRequestOperation does not seem to have any negative effects, and everything is operating as expected and thus my main question is are these two functions different in any significant way where given my described use-case I should prefer one to the other?
A secondary question to this is I'm using CocoaLumberjack to handle debug logging to the console/file, and I'd like the raw JSON (prior to being mapped to objects) to be logged for debugging. The only solution I've found to do this is to do something like this:
[operation setWillMapDeserializedResponseBlock:^id(id deserializedResponseBody) {
DDLogInfo(#"%#", deserializedResponseBody);
return deserializedResponseBody;
}];
This worked before when I was doing a managedObjectRequestOperation, as doing so involved creating an instance of it before configuring it further and telling it to start, but using something the object manager's postObject function as described doesn't involve creating/returning an instance of the operation that I can set the willMapDeserializedResponseBlock on... Any ideas?

You should prefer postObject:path:parameters:success:failure because it's the higher level API. The difference is that the operation gives you more access to the underlying system and request, but if you don't need that you should let the manager handle it for you.
For debug purposes you can use
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
or a lower level.

Related

What happens if the `NEPacketTunnelflow` method `readPacketsWithCompletionHandler` is called multiple times?

When calling the method
- (void)readPacketsWithCompletionHandler:(void (^)(
NSArray<NSData *> *packets, NSArray<NSNumber *> *protocols))completionHandler;
the completionHandler is either called directly, in case packets are available at call time, or it is called at a later tim when packets become available.
Yet what is nowhere documented is: What happens if I call this method again before the prior set completionHandler has ever been called?
Will the new handler replace the prior set one and the prior set one won't get called at all anymore?
Are both handler scheduled and called as data arrives? And if so, will they be called in the order I passed them, in reverse order, or in random order?
Has anyone any insights on how that method is implemented?
Of course, I can make a demo project, create a test setup, and see what results I get through testing but that is very time consuming and not necessarily reliable. The problem with unspecified behavior is that it may change at will without letting anyone know. This method may behave differently on macOS and iOS, it may behave differently with every new OS release, or depending on the day of the week.
Or does the fact that nothing is documented is by intention? Do I have to interpret that as: You may call this method once and after your callback was executed, you may call it again with the same or a new callback. Everything else is undefined behavior and you cannot and should not rely on any specific behavior if use that API in a different manner.
As nobody has replied so far, I tried my best to figure it out myself. As testing is not good enough for me, here is what I did:
First I extracted the NetworkExtension framework binary from the dyld cache of macOS Big Sur using this utility.
Then I ran otool -Vt over the resulting binary file to get a disassembler dump of the binary.
My assembly skills are a bit rusty but from what I see the completionHandler is stored in a property named packetHandler, replacing any previous stored value there. Also a callback is created in that method and stored on an object obtained by calling the method interface.
When looking at the code of this created callback, it obtains the value of the packetHandler property and sets it to NULL after the value was obtained. Then it creates NSData and NSNumber objects, adds those to NSArray objects and calls the obtained handler with those arrays.
So it seems that calling the method again just replaces the previous completionHandler which is never be called in that case. So you must not rely that a scheduled handler will eventually be called at some time in the future if the tunnel is not teared down if the possibility exists that your code might replace it. Also calling the method multiple times to schedule multiple callbacks has no effect as as only the last one will be kept and eventually be called.

Delegation pattern vs error handling in Swift

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.

iOS: How to check if #selector has been called and then continue on the for loop?

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.

Setting NSOutputStream to be synchronous

I know there are few questions similar to this one, but in all cases the answer is to make it asynchronous.
According to the apple documentation (even though it is not recommended) polling is an available option. However, I just couldn't implement it.
Should probably mention I am doing it in c# using Xamarin, but if you
can give me an answer on how to do this in Objective-C that would be
good too.
Here is my attempt
while(true)
{
if (outStream.HasSpaceAvailable())
{
int output = ((NSOutputStream)outStream).Write(data, (uint)data.Count());
}
}
The problem here is that outStream.HasSpaceAvailable() is false indefinitely.
Reason why I want to do it synchronously:
Currently (in a test app) I am doing it asynchronously and it works for sending one stream of data per call to the method. However in the real App I will need to send lots of small data packets one after the other. Therefore, I need to wait for the data to be sent before I can send another packet.
If I try putting many calls to the delegate the data keeps overwriting the previous call...
It would be great if you could let me know how to do it synchronously first (for the sake of having one answer out there on it). If you think there is a better way to do it in an async way let me know too.
Thanks
EDIT :
Here is how I set up the session
SESSION=new EASession (Accessory, Protocol);
NSStreamStatus outputStream= SESSION.OutputSream;
outputStream.Open();
This is done when a button is pressed and before the while loop above (obviously).

Debugging NSManagedObjectContext

At debugging time, if I have an NSManagedObjectContext, is there a way to look inside to see what objects are in it.
Basically I'm having a save error since there's a CGColor being saved which is not NSCoding compliant. But I have no idea where this CGColor comes from.
Well, step back for a second and think about where your error is stemming from.
You're trying to encode a CGColorRef via the NSCoding mechanism. This is obviously not supported and will cause an exception to be thrown. You should add an exception breakpoint in your debugger to introspect where this faulty assignment is being executed. You should then be able to figure out your issue.
If you find that this is somehow unrelated to your problem, then you can indeed introspect the objects which are laying around in your context via the -registeredObjects method.
I agree with JR (below) that you should set an exception breakpoint to get a stack trace at the point of failure.
One other thought: although autosaving is convenient, it doesn't always happen at the best time for debugging. You might find it helpful to put in a debugging operation that forces an explicit save when you want to validate your object:
[self.document closeWithCompletionHandler:^(BOOL success) {
if (!success) NSLog(#“failed to close document %#”, self.document.localizedName);
}];
With this, or something like it, you can initiate saving at various points to see when your object becomes corrupted. Do keep in mind that saving is asynchronous.

Resources