mergeChangesFromContextDidSaveNotification taking up all space - macos

I'm implementing iCloud + Core Data for Mac OS and I'm having a major issue with mergeChangesFromContextDidSaveNotification.
When NSPersistentStoreDidImportUbiquitousContentChangesNotification is posted, I'm calling the following method:
- (void)mergeChangesFromNotification:(NSNotification *)note
{
self.managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
[self.managedObjectContext performBlock:^{
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:note];
}];
// ....
}
The problem is that mergeChangesFromContextDidSaveNotification: does not return and, also, takes up more and more memory until the system runs out space.
Any thoughts on what the problem might be? I'm doing almost the same thing on iOS and works just fine.
Thanks!

I finally found the bug - and as I expected, it was quite stupid one:
I was merging the changes into the wrong context.

Related

Swift 2, warning: could not load any Objective-C class information from the dyld shared cache

I have found a few questions regarding this issue, yet none of them were helping with my problem. I am trying to save an object to core data using this code (which worked perfectly fine in Xcode 6 and Simulator...):
let fetchRequest = NSFetchRequest(entityName: "Patient")
let fetchedResults : [NSManagedObject]!
do {
fetchedResults = try managedContext.executeFetchRequest(fetchRequest) as! [NSManagedObject]
patienten = fetchedResults
} catch {
print("error")
}
I added the do-try-catch once I started working on this project in the Xcode 7 beta and a physical device.
Now, when I hit the Save button, this piece of code is called, the app freezes and I get the following:
warning: could not load any Objective-C class information from the dyld shared cache. This will significantly reduce the quality of type information available.
Does anybody know where I went wrong?
For anyone coming across this in the future, I just ran into this problem myself and it turned out that I was actually getting a stack overflow from a recursive function.
Apparently calling setValue:forKey: on an NSObject calls the respective set[Key] function, where [Key] is the (capitalized) name you gave to the forKey section.
So, if like me, you have code that looks like the following, it will cause an infinite loop and crash.
func setName(name: String) {
self.setValue(name, forKey: "name")
}
Choose Product > Clean
I had similar issue. I deleted the app from the device. Then "Product->Clean" in the XCode menu. When I ran the app again, the issue got resolved.
Swift 3:
Actually this problem happened often when you have any property in input declared as type NSError and the compiler expect an Error output, so change the input type to Error usually solve this issue.
What helped me in similar problem (xCode 7, Swift 2):
reading this question
Or more quickly without explaining the reason of solution: just comment #objc(className) in your NSManagedObjectSubclass , that was generated from your CoreData Entity (#objc(Patient) - in your case ).
This solution (if issue still appears) does not applicable to xCode 7.1/Swift 2.1, as the way of generating NSManagedObjectSubclasses was changed.
Don't forget about cleaning your project (Product > Clean) and deleting the app from your device/simulator to replace CoreData storage on it.
let fetchRequest = NSFetchRequest(entityName: "Patient")
do {
let fetchedResults = try managedObjectContext!.executeFetchRequest(fetchRequest)
print("\(fetchedResults)")
} catch {
print("error")
}
The above code worked for me.
Maybe the issue maybe with how your core data is managed.
Check if your managedObjectContext is actually getting created.
Check the modelling of your core data

NSData dataWithContentsOfURL returning nil specifically in iOS 8

I am tring to get the NSData from a local file using [NSData dataWithContentsOfURL:] but am getting nil even when the fileSize returned by [NSFileManager defaultManager] is a positive integer.
Surprisingly, I got this issue when the base sdk was increased from iOS 7 to iOS 8.
I am not sure whether it is an iOS bug or what as it worked in iOS 7 base SDK and not with iOS 8, but here is the solution I found after wasting a couple of hours debugging the code :-(
Use [NSData dataWithContentsOfFile:(NSString *)] instead of dataWithContentsOfURL
Are you sure you pass the Bundle path as well ?
Try with this
NSString* path = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:yourPath];
NSData* data = [NSData dataWithContentsOfURL:path];
NSData and URLs: There be dragons
+[NSData dataWithContentsOfURL:] can return nil for any number of reasons. If anything goes wrong when attempting to use that URL this method will return nil. For example the file may not exist, the network connection may time out, or the URL may even be malformed. nil is returned and the application has no idea why.
+ [NSData dataWithContentsOfURL:options:error:] on the other hand, will tell the caller what went wrong. When nil is returned the error argument will be populated with an object that describes the problem that occured. Using this method would directly answer the question of "why".
Both of these are synchronous methods and their use for working with files, network resources, and especially files served from a network resource is discouraged. These methods will block the caller and are not really intended for these kinds of uses. It's better to use an input stream or NSURLSession instead.
you can reference enter link description here
My case. it had a space in the URL
remove space

CMPedometer is not running

My CMPedometer is not running.
The code before it and after it gets run, but it itself does not work.
I get no warning or exception.
I'm testing it on a real 5s.
I've tried both querydata and startpedometerupdates.
I am importing core motion and the library is linked.
Any help?
if ([CMPedometer isStepCountingAvailable] == YES)
{
CMPedometer *cmped;
[cmped queryPedometerDataFromDate:start toDate:[NSDate date] withHandler:^(CMPedometerData *pedometerData, NSError *error){
stepslabel.text = [pedometerData.numberOfSteps stringValue];
}];
}
The problem with the original code above is the cmped variable gets deallocated at the end of the if statement, so the query is destroyed before it finishes.
By changing it to a strong property, it is retained in memory for the life of the class.
It seems really odd but I got it working by not declaring in the .h or before using it. What worked was declaring as #property CMPedometer *cmped; right after interface

CIDetector trackingID never present

I'm working on some face detection code on OSX Mavericks and I'm trying to take advantage of the newish (as of 10.8) face tracking across multiple stills functionality that CIDetector offers.
I have basic face detection working fine, like so:
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection {
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CIImage *image = [CIImage imageWithCVImageBuffer:imageBuffer];
CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace
context:nil
options:#{ CIDetectorAccuracy : CIDetectorAccuracyHigh,
CIDetectorTracking : #YES
}];
NSArray *features = [faceDetector featuresInImage:image];
for ( CIFaceFeature *feature in features ) {
if (feature.hasTrackingID) {
NSLog(#"tracking id: %#", #(feature.trackingID));
}
}
}
The features list does get populated correctly but that trackingID never seems to be present.
Has anyone gotten this working on Mavericks? It fails the same way on Mountain Lion.
I have seen a similar question here (CIFaceFeature trackingID is always coming same for multiple faces) but I didn't learn anything new there.
For what it's worth it does seem to function correctly on iOS.
I looked at this code again and the answer turned out to be pretty obvious: I was constantly re-initializing the CIDetector, which was bad for performance and also had the consequence of resetting its internal tracking data each frame. So the first time a face was detected was always the first time a face was detected for that particular CIDetector instance.
Also, CIDetector warns about this in the docs:
"This class can maintain many state variables that can impact performance. So for best performance, reuse CIDetector instances instead of creating new ones.", from https://developer.apple.com/library/mac/documentation/CoreImage/Reference/CIDetector_Ref/Reference/Reference.html.

Know if MainApp is launched by HelperApp

I am really stuck here with a simple task, but still cannot get it working.
I've managed to implement 'LaunchAtLogin' feature with the HelperApp as described in this article.
But my application should react differently on launch-by-helper-app and launch-by-user actions. So my task now is to have some kind of flag indicating that MainApp was launched by HelperApp.
I know there are many similar questions, but still none of the solutions works for me. Sandbox seems to cut all the parameters I am trying to send to the MainApp.
Here what I have tried:
- [NSWorkspace - launchApplicationAtURL: options: configuration: error:]
- [NSWorkspace - openURLs: withAppBundleIdentifier: options: additionalEventParamDescriptor: launchIdentifiers:]
- LSOpenApplication()
Until recently I thought I can rely on -psn argument sent by Finder when user manually launches the application. But this argument is sent on 10.8 even when MainApp is launched by HelperApp.
In the article mentioned above, author suggests using [NSWorkspace - launchApplicationAtURL: options: configuration: error:]. Parameters are sent, but nothing arrives to the MainApp.
Has anyone succeeded to accomplish this (or similar) task?
Need help!
Thanks in advance!
After hell of searching and experimenting I am ready to answer my own question, so others can save their time and efforts.
My conclusion is that for now there is no way HelperApp can launch MainApp with some arguments under the Sandbox. At least I have not found any way to do that.
Launch MainApp like this:
[[NSWorkspace sharedWorkspace] launchApplication:newPath];
In MainApp add the following:
Application_IsLaunchedByHelperApp = YES;
ProcessSerialNumber currPSN;
OSStatus err = GetCurrentProcess(&currPSN);
if (!err)
{
// Get information about our process
NSDictionary * currDict = [(NSDictionary *)ProcessInformationCopyDictionary(&currPSN,
kProcessDictionaryIncludeAllInformationMask) autorelease];
// Get the PSN of the app that launched us. Its not really the parent app, in the unix sense.
long long temp = [[currDict objectForKey:#"ParentPSN"] longLongValue];
long long hi = (temp >> 32) & 0x00000000FFFFFFFFLL;
long long lo = (temp >> 0) & 0x00000000FFFFFFFFLL;
ProcessSerialNumber parentPSN = {(UInt32)hi, (UInt32)lo};
// Get info on the launching process
NSDictionary * parentDict = [(NSDictionary*)ProcessInformationCopyDictionary(&parentPSN,
kProcessDictionaryIncludeAllInformationMask) autorelease];
// analyze
// parent app info is not null ?
if (parentDict && parentDict.count > 0)
{
NSString * launchedByAppBundleId = [parentDict objectForKey:#"CFBundleIdentifier"];
if (![launchedByAppBundleId isEqualToString:HELPER_APP_BUNDLE_ID])
{
Application_IsLaunchedByHelperApp = NO;
}
}
}
That's it. Application_IsLaunchedByHelperApp now has correct value.
The solution is not mine. I've found it on the web (cocoabuilder, I guess). Good luck to everyone! And thanks for your attention to my questions.
UPDATE
Looks like there are cases when launched at login app shows launchedByAppBundleId = #"com.apple.loginwindow". So the last part of code will look like this:
//
// analyze
//
// parent app info is not null ?
if (parentDict && parentDict.count > 0)
{
NSString * launchedByAppBundleId = [parentDict objectForKey:#"CFBundleIdentifier"];
if (![launchedByAppBundleId isEqualToString:HELPER_APP_BUNDLE_ID] &&
![launchedByAppBundleId isEqualToString:#"com.apple.loginwindow"])
{
Application_IsLaunchedByHelperApp = NO;
}
}
The place to seek an answer is the Apple Developer Forums - folk there have dealt with all sorts of issues around helper apps and the sandbox. Searching for application groups and custom URL schemes going back, say, 1-2 years may turn up a solution that meets your needs. If you are still stuck post a question on those forums, someone will probably know what you need.
If you are not an Apple Developer so have no access to those forums, or do not intend to distribute via the Mac App Store, then just turn off the sandbox - in its current state this isn't technology you choose to use... HTH.

Resources