NSOperation Causing Crash when Passed to Delegate - cocoa

For an iPhone app, I'm using a NSOperationQueue to limit access to the SQLite database to one query at a time. I created a subclass of NSOperation and in the main function I have the following:
- (void)main
{
// ... other code here ...
if( [_delegate respondsToSelector:#selector(queryCompleted:)] )
{
[_delegate performSelectorOnMainThread:#selector(queryCompleted:)
withObject:self
waitUntilDone:NO];
}
}
Delegate side:
- (void)queryCompleted:(QueryOperation*)aQueryOperation
{
// Breakpoint here allows me to explore and see the members of aQueryOperation
id results = [aQueryOperation resultSet]; // Crashes here
// ... more code here ...
}
The reason I am passing self is to allow the delegate to access the ID for the query operation (in the case where there is more than one request open per delegate) and the results from the query.
In the documentation for performSelectorOnMainThread:withObject:waitUntilDone:, it clearly states:
"This method retains the receiver and the arg parameter until after the selector is performed."
However when the delegate method tries to access the argument, an "EXC_BAD_ACCESS" exception is thrown. Any thoughts on why?
Oddly enough, if I set a breakpoint before the crashing reference to the NSOperation object, the debugger permits me to see the object instance and the values of all the parameters.

Try setting the waitUntilDone: parameter to YES. Possibly there is a race condition which is allowing the NSOperation to deallocate itself.

Related

OCMock - Mocking nested blocks

I am testing the following method with OCMock:
- (void)methodToTest {
[self.someObject doFirstActionWithParam:#"aparam" completion:(void(^)(BOOL success)) {
if (success) {
[self.someObject doSecondActionWithParam:#"aparam" completion:(void(^)(BOOL success)) {
if (success) { [self doSomething]; }
}];
}
}];
}
I have a partial mock for self.someObject.
The doFirstActionWithParam, I am able to set an expectation for. I am also overriding the completion block (via NSInvocation and invoking a YES completion).
However, I am not able to get the call for doSecondActionWithParam method. I also set up expectation for doSomething method. That never comes through.
Any suggestion for an approach to test nested completion blocks?
There shouldn't be a difference due to the nesting level when you mock a method (stub or expect). As you didn't include your test code it's really difficult to diagnose the problem. My assumption is that the block that is passed to doFirstActionWithParam:completion: is never invoked, in which case doSecondActionWithParam:completion: would als never be invoked.

NSManagedObjectContext(): `init()` was deprecated in iOS 9.0: Use -initWithConcurrencyType

I was working through Core Data Stack in Swift - Demystified but when I got to the line
self.context = NSManagedObjectContext()
I got the warning
`init()` was deprecated in iOS 9.0: Use -initWithConcurrencyType: instead
I see that I can do one of the following for self.context =
NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.ConfinementConcurrencyType)
NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
but since ConfinementConcurrencyType is also deprecated now that leaves me MainQueueConcurrencyType and PrivateQueueConcurrencyType. What is the difference between these two and how should I choose which one to use? I read this documentation, but I didn't really understand.
You essentially will always have at least 1 context with NSMainQueueConcurrencyType and many contexts with NSPrivateQueueConcurrencyType. NSPrivateQueueConcurrencyType is used typically for saving or fetching things to core data in the background (like if attempting to sync records with a Web Service).
The NSMainQueueConcurrencyType creates a context associated with the main queue which is perfect for use with NSFetchedResultsController.
The default core data stack uses a single context with NSMainQueueConcurrencyType, but you can create a much better app by leveraging multiple NSPrivateQueueConcurrencyType to do any work that does not affect the UI.
Replace these two function with the following one:
lazy var managedObjectContext: NSManagedObjectContext = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
abort()
}
}
}

NSManagedObjectContext save unsuccessful, but returns nil error

I am developing an OS X Application that uses a single-threaded Core Data model without nested contexts.
I am creating objects on the main thread in the defaultContext and try to save them after creation, but the save fails without returning an error. I have not overwritten any methods in my CoreData objects, but I am using the latest version of MagicalRecord.
The code that fails:
// pseudocode for createOrFetchWithData:inContext:
// fetch object from value in objectDict
// if(!object) create project in context
// [object importValuesForKeysWithObject:objectData] // MR method
// return object
MyObject *object = [MyObject createOrFetchWithData:objectData
inContext:[NSManagedObjectContext defaultContext]];
if(!object) return; // just to emphasise that I am sure the object is not nil.
[[NSManagedObjectContext defaultContext] saveOnlySelfWithCompletion:^(BOOL saveSuccessful, NSError *error) {
if(saveSuccessful) {
NSLog(#"yay");
} else {
NSLog(#"nay");
}
}];
The return value of [NSManagedObjectContext defaultContext] is not nil and I have verified that the code is executed on the main thread.
I have a relationship that isn't set in the MyObject *object, but it is marked as optional in the data model.
Any idea what might cause this simple operation to fail? I have other entities that save just fine, but this particular case fails.
Note: I am running OS X Mavericks DP 8.
In the end, it was my misunderstanding of MagicalRecord's (and possibly CoreData's) implementation of the save: methods: in case there is no change to the context ([context hasChanges] == NO) AND the parent context (!!), the save will be aborted, and the completion block is called with NO for successful and no error object.

How to properly use Cocos2d's update/tick method to trigger an event, only once?

I keep running into this issue wherein I'd like to trigger an event (void) during a scheduled update or tick method - but only trigger it once. The problem is that it gets triggered every time update/tick gets called (each frame). Depending on what method is being called, this slows down the game and occasionally crashes (e.g. addChild already added). I've used a BOOL (e.g. eventTriggered) before to try to handle this situation but am wondering if that is the only and/or best way?
If you're using cocos2d 2.0 just use:
[self scheduleOnce:#selector(yourMethod:) delay:3.0f];
In all other cases simply unschedule the scheduled selector:
-(void) yourScheduledMethodThatShouldOnlyRunOnce:(ccTime)delta
{
[self unschedule:_cmd];
// do stuff once
}
If it's a custom method you need to have some condition that fires the method call, for example:
-(void) update:(ccTime)delta
{
if (runThisNowButOnlyOnce)
{
runThisNowButOnlyOnce = NO;
[self runThisNowButOnlyOnceMethod];
}
}
You just need to figure out when and where to set runThisNowButOnlyOnce to YES. Also don't forget to add it as an ivar to the #interface.

RestKit Best practices with the sendSynchronously method

I am trying to load objects synchronously with RestKit and to do that I am using [anObjectLoader sendSynchronously] on a background thread. Then in the RKObjectLoader didFinishLoad: the application is currently stopping at the first line: NSAssert([NSThread isMainThread], #"RKObjectLoaderDelegate callbacks must occur on the main thread");
Looking at the documentation, the sendSynchronously method from the RKRequest class says that the request will be synchronously requested and a hydrated response object will be returned.
This is a snapshot of my code:
RKObjectLoader *anObjectLoader = [self.objectManager loaderWithResourcePath:resourcePath];
NSLog(#"Response: %#", [anObjectLoader sendSynchronously]);
On console:
*** Assertion failure in -[RKManagedObjectLoader didFinishLoad:], ...RestKit/Code/ObjectMapping/RKObjectLoader.m:423
Is it Ok to use RestKit with synchronous calls?
Are there better ways to send synchronous requests?
Am I missing something?
You should never make synchronous calls. Use the send method and catch the response using either delegates or block callbacks. Among other things, this method is optimized for network bandwidth usage and also handles threading correctly.
As an aside, the reason RKObjectLoader requires the main thread is because that is where your main object context is.
I recently had this same question. I figured out how to send a synchronous call using blocks and it's actually quite nice. Basically you do whatever restkit call you were intending to do, but instead of setting the delegate to self, you use usingBlock. Then, within that block you can handle the various responses from your API call.
Block Example (APIUser is class I wrote that represents the current user):
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[#"/api/users/" stringByAppendingString:userName] usingBlock:^(RKObjectLoader* loader) {
loader.onDidLoadResponse = ^(RKResponse *response) {
NSLog(#"Response: \n%#", [response bodyAsString]);
};
loader.onDidLoadObjects = ^(NSArray *objects) {
APIUser *apiUser = [objects objectAtIndex:0];
};
loader.onDidFailWithError = ^(NSError *error) {
NSLog(#"Response: \n%#", [response bodyAsString]);
};
}];
My original question and answer can be found here.

Resources