UIDocumentInteractionController weird behaviour on iphone with iOS7 - ios7

I am hitting the wall with a problem for two days now and i would like your help. Before i start i should say that this problem is on iPhone 5 with iOS7 (I have also tested on iPhone 4 with iOS 6 and iPad 2 with iOS 7). This problem began when i tried to upgrade an application that has been on AppStore (iOS4 initially) and tried to make it iOS 7 compatible (supported on iOS6 onwards).
The scenario is pretty simple. I have a view with is a UIDocumentInteractionControllerDelegate. I download a file from a web service save it on the NSTemporaryDirectory and allow the user to Preview or Open In another app using the presentOptionsMenuFromRect. The code simplified is as follow:
I have declared a #property (nonatomic, strong) UIDocumentInteractionController *docController;
#autoreleasepool {
NSString *fileName = "uniquefilename"
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
fileURL = [NSURL fileURLWithPath:filePath];
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:filePath]){
NSData *fileData = [NSData dataWithContentsOfURL:[NSURL URLWithString:"theurlofthefile"]];
NSError *writeError = nil;
[fileData writeToURL: fileURL options:0 error:&writeError];
if(writeError) {
//show error
}
}
docController = [UIDocumentInteractionController interactionControllerWithURL:url];
docController.delegate = self;
if (isIpad) {
[docController presentOptionsMenuFromRect:CGRectMake(location.x + 400,location.y, 100, 100) inView:tableView animated:YES];
}
else{
[docController presentOptionsMenuFromRect:CGRectZero inView:self.tabBarController.view animated:YES];
}
}
The problem is that i receive all kind of errors, i repeat the same process all the time and i get different errors, sometimes it works for many times in a row, sometimes it fails from the first go. The errors i receive amongst others which i will add when i get them again are:
* Terminating app due to uncaught exception 'NSGenericException', reason: '* Collection <__NSSetM: 0x16ff61e0> was mutated while
being enumerated.'
malloc: * error for object 0x177a56a4: incorrect checksum for
freed object - object was probably modified after being freed.
malloc: * error for object 0x1c2c8b50: double free * set a
breakpoint in malloc_error_break to debug
When the OptionsMenu is showed successfully i see "AirDrop: collectionView:layout:insetForSectionAtIndex:, orientation: 1, sectionInset: {0, 10, 0, 10}" in the console.
I tried enabling NSZombies and putting a breakpoint for malloc error but did not help me in any way.
Please help me or guide me to the right direction.
Thank you.

Bit late to answer, but hopefully it will help other people.
I had exactly the same issue when saving a file and presenting a UIDocumentInteractionController, it was absolutely random sometimes it would would perfectly 10 times in a row and sometimes it would crash on first try.
It seems to be caused by the file not having finished writing to disk, what fixed it for me was adding a delay before presenting the UIDocumentInteractionController to ensure that the file has finished writing to disk

Related

NSString pathway always returns nil despite having the file contained in the folder

So i'm trying to create a video screen saver for macOS 10.12 by using NSString to obtain the pathway, and NSURL to store the pathway.
However every time I test the screen saver, it crashes with this error:
Application Specific Information:
com.apple.preference.desktopscreeneffect v.5.1 (Desktop & Screen Saver)
Crashing on exception: *** -[NSURL initFileURLWithPath:]: nil string parameter
I believe the problem lies here:
// Create the video path then use it. (Problem at the moment: the pathway always returns nil)
NSString *screenSaverPath = [[NSBundle mainBundle] pathForResource:#"apple" ofType:#"mp4"];
NSURL *screenSaver = [NSURL fileURLWithPath:screenSaverPath];
//Obtain the size of the screen.
NSSize size = [self bounds].size;
//Draw the video player.
AVPlayer *video = [AVPlayer playerWithURL:screenSaver];
But I am unsure as to how I can tackle this problem. Does anyone know any way as to how you can resolve this problem? Thank you!
Screen savers are loaded into an application. So mainBundle is the ScreenSaverEngine process that loaded your plugin, not your plugin. You should probably use bundleForClass to get the bundle your screensaver's main class is in.

Issue with ELC Image Picker when too many images are selected iPhone

I am using ELC Image Picker in my project. Here i am getting one issue that is:
when i selected images like 20 picker is working fine but when I select images like 32(selected images count) my app is crashing before dismissal of controller itself and I am getting the error:
Program received signal: “0”. Data Formatters temporarily
unavailable, will re-try after a 'continue'. (Unknown error loading
shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
And also I am getting:
Received memory warning. Level=1
NOTE: when this situation is happened is, first i selected 32 images worked fine and again I selected same number of images it was crashing.
Also I've tried with the example: github ELCImagePickerController project.
Can any one give me the answer to over come this?
From error you can see that its a memory issue
So you have 2 options
set a limit for number of images can be choosed
in background save images to temp folder
OR
Customize ELC picker code so that...when a person selects an image... it will take only image path but not image content
and when they are done... now run a loop to get those images into your app.
#SteveGear following code will solve your problem. Just provide the UIImagePickerControllerReferenceURL and you will get the NSData. Its long time but still, it may help others.
ALAssetsLibrary *assetLibrary=[[ALAssetsLibrary alloc] init];
NSURL *assetURL = [infoObject objectForKey:UIImagePickerControllerReferenceURL];
__block NSData *assetData;
[assetLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) // substitute assetURL with your url
{
ALAssetRepresentation *rep = [asset defaultRepresentation];
Byte *buffer = (Byte*)malloc((long)rep.size);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:(NSUInteger)rep.size error:nil];
assetData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];//this is NSData what you need.
//[data writeToFile:assetData atomically:YES]; //Uncomment this if you want to store the data as file.
}
failureBlock:^(NSError *err) {
NSLog(#"Error: %#",[err localizedDescription]);
}];
Here assetData is what you need.

Calling -[NSFileManager setUbiquitous:itemAtURL:destinationURL:error:] never returns

I have a straightforward NSDocument-based Mac OS X app in which I am trying to implement iCloud Document storage. I'm building with the 10.7 SDK.
I have provisioned my app for iCloud document storage and have included the necessary entitlements (AFAICT). The app builds, runs, and creates the local ubiquity container Documents directory correctly (this took a while, but that all seems to be working). I am using the NSFileCoordinator API as Apple recommended. I'm fairly certain I am using the correct UbiquityIdentifier as recommended by Apple (it's redacted below tho).
I have followed Apple's iCloud Document storage demo instructions in this WWDC 2011 video closely:
Session 107 AutoSave and Versions in Lion
My code looks almost identical to the code from that demo.
However, when I call my action to move the current document to the cloud, I experience liveness problems when calling the -[NSFileManager setUbiquitous:itemAtURL:destinationURL:error:] method. It never returns.
Here is the relevant code from my NSDocument subclass. It is almost identical to Apple's WWDC demo code. Since this is an action, this is called on the main thread (as Apple's demo code showed). The deadlock occurs toward the end when the -setUbiquitous:itemAtURL:destinationURL:error: method is called. I have tried moving to a background thread, but it still never returns.
It appears that a semaphore is blocking while waiting for a signal that never arrives.
When running this code in the debugger, my source and destination URLs look correct, so I'm fairly certain they are correctly calculated and I have confirmed the directories exist on disk.
Am I doing anything obviously wrong which would lead to -setUbiquitous never returning?
- (IBAction)moveToOrFromCloud:(id)sender {
NSURL *fileURL = [self fileURL];
if (!fileURL) return;
NSString *bundleID = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleIdentifier"];
NSString *appID = [NSString stringWithFormat:#"XXXXXXX.%#.macosx", bundleID];
BOOL makeUbiquitous = 1 == [sender tag];
NSURL *destURL = nil;
NSFileManager *mgr = [NSFileManager defaultManager];
if (makeUbiquitous) {
// get path to local ubiquity container Documents dir
NSURL *dirURL = [[mgr URLForUbiquityContainerIdentifier:appID] URLByAppendingPathComponent:#"Documents"];
if (!dirURL) {
NSLog(#"cannot find URLForUbiquityContainerIdentifier %#", appID);
return;
}
// create it if necessary
[mgr createDirectoryAtURL:dirURL withIntermediateDirectories:NO attributes:nil error:nil];
// ensure it exists
BOOL exists, isDir;
exists = [mgr fileExistsAtPath:[dirURL relativePath] isDirectory:&isDir];
if (!(exists && isDir)) {
NSLog(#"can't create local icloud dir");
return;
}
// append this doc's filename
destURL = [dirURL URLByAppendingPathComponent:[fileURL lastPathComponent]];
} else {
// get path to local Documents folder
NSArray *dirs = [mgr URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
if (![dirs count]) return;
// append this doc's filename
destURL = [[dirs objectAtIndex:0] URLByAppendingPathComponent:[fileURL lastPathComponent]];
}
NSFileCoordinator *fc = [[[NSFileCoordinator alloc] initWithFilePresenter:self] autorelease];
[fc coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForMoving writingItemAtURL:destURL options:NSFileCoordinatorWritingForReplacing error:nil byAccessor:^(NSURL *fileURL, NSURL *destURL) {
NSError *err = nil;
if ([mgr setUbiquitous:makeUbiquitous itemAtURL:fileURL destinationURL:destURL error:&err]) {
[self setFileURL:destURL];
[self setFileModificationDate:nil];
[fc itemAtURL:fileURL didMoveToURL:destURL];
} else {
NSWindow *win = ... // get my window
[self presentError:err modalForWindow:win delegate:nil didPresentSelector:nil contextInfo:NULL];
}
}];
}
I don't know if these are the source of your problems, but here are some things I'm seeing:
-[NSFileManager URLForUbiquityContainerIdentifier:] may take a while, so you shouldn't invoke it on the main thread. see the "Locating the Ubiquity Container" section of this blog post
Doing this on the global queue means you should probably use an allocated NSFileManager and not the +defaultManager.
The block passed to the byAccessor portion of the coordinated write is not guaranteed to be called on any particular thread, so you shouldn't be manipulating NSWindows or presenting modal dialogs or anything from within that block (unless you've dispatched it back to the main queue).
I think pretty much all of the iCloud methods on NSFileManager will block until things complete. It's possible that what you're seeing is the method blocking and never returning because things aren't configured properly. I'd double and triple check your settings, maybe try to simplify the reproduction case. If it still isn't working, try filing a bug or contacting DTS.
Just shared this on Twitter with you, but I believe when using NSDocument you don't need to do any of the NSFileCoordinator stuff - just make the document ubiquitous and save.
Hmm,
did you try not using a ubiquity container identifier in code (sorry - ripped out of a project so I've pseudo-coded some of this):
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *iCloudDocumentsURL = [[fm URLForUbiquityContainerIdentifier:nil] URLByAppendingPathComponent:#"Documents"];
NSURL *iCloudFileURL = [iCloudDocumentsURL URLByAppendingPathComponent:[doc.fileURL lastPathComponent]];
ok = [fm setUbiquitous:YES itemAtURL:doc.fileURL destinationURL:iCloudRecipeURL error:&err];
NSLog(#"doc moved to iCloud, result: %d (%#)",ok,doc.fileURL.fileURL);
And then in your entitlements file:
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>[devID].com.yourcompany.appname</string>
</array>
Other than that, your code looks almost identical to mine (which works - except I'm not using NSDocument but rolling it all myself).
If this is the first place in your code that you are accessing iCloud look in Console.app for a message like this:
taskgated: killed yourAppID [pid 13532] because its use of the com.apple.developer.ubiquity-container-identifiers entitlement is not allowed
Anytime you see this message delete your apps container ~/Library/Containers/<yourAppID>
There may also be other useful messages in Console.app that will help you solve this issue.
I have found that deleting the app container is the new Clean Project when working with iCloud.
Ok, So I was finally able to solve the problem using Dunk's advice. I'm pretty sure the issue I was having is as follows:
Sometime after the WWDC video I was using as a guide was made, Apple completed the ubiquity APIs and removed the need to use an NSFileCoordinator object while saving from within an NSDocument subclass.
So the key was to remove both the creation of the NSFileCoordinator and the call to -[NSFileCoordinator coordinateWritingItemAtURL:options:writingItemAtURL:options:error:byAccessor:]
I also moved this work onto a background thread, although I'm fairly certain that was not absolutely required to fix the issue (although it was certainly a good idea).
I shall now submit my completed code to Google's web crawlers in hopes of assisting future intrepid Xcoders.
Here's my complete solution which works:
- (IBAction)moveToOrFromCloud:(id)sender {
NSURL *fileURL = [self fileURL];
if (!fileURL) {
NSBeep();
return;
}
BOOL makeUbiquitous = 1 == [sender tag];
if (makeUbiquitous) {
[self displayMoveToCloudDialog];
} else {
[self displayMoveFromCloudDialog];
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doMoveToOrFromCloud:makeUbiquitous];
});
}
- (void)doMoveToOrFromCloud:(BOOL)makeUbiquitous {
NSURL *fileURL = [self fileURL];
if (!fileURL) return;
NSURL *destURL = nil;
NSFileManager *mgr = [[[NSFileManager alloc] init] autorelease];
if (makeUbiquitous) {
NSURL *dirURL = [[MyDocumentController instance] ubiquitousDocumentsDirURL];
if (!dirURL) return;
destURL = [dirURL URLByAppendingPathComponent:[fileURL lastPathComponent]];
} else {
// move to local Documentss folder
NSArray *dirs = [mgr URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
if (![dirs count]) return;
destURL = [[dirs firstObject] URLByAppendingPathComponent:[fileURL lastPathComponent]];
}
NSError *err = nil;
void (^completion)(void) = nil;
if ([mgr setUbiquitous:makeUbiquitous itemAtURL:fileURL destinationURL:destURL error:&err]) {
[self setFileURL:destURL];
[self setFileModificationDate:nil];
completion = ^{
[self hideMoveToFromCloudDialog];
};
} else {
completion = ^{
[self hideMoveToFromCloudDialog];
NSWindow *win = [[self canvasWindowController] window];
[self presentError:err modalForWindow:win delegate:nil didPresentSelector:nil contextInfo:NULL];
};
}
dispatch_async(dispatch_get_main_queue(), completion);
}

AVAsset has no tracks or duration when created from an ALAsset URL

I'm pulling all of the video assets from ALAssetsLibrary (Basically everything that's being recorded from the native camera app). I am then running an enumeration on each video asset that does this to each video:
// The end of the enumeration is signaled by asset == nil.
if (alAsset) {
//Get the URL location of the video
ALAssetRepresentation *representation = [alAsset defaultRepresentation];
NSURL *url = [representation url];
//Create an AVAsset from the given URL
NSDictionary *asset_options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
AVAsset *avAsset = [[AVURLAsset alloc] initWithURL:url options:asset_options];//[AVURLAsset URLAssetWithURL:url options:asset_options];
//Here is the problem
NSLog([NSString stringWithFormat:#"%i", [avAsset.tracks count]]);
NSLog([NSString stringWithFormat:#"%f", CMTimeGetSeconds(avAsset.duration)]);
}
NSLog is reporting that the AVAsset that I've gotten from my ALAsset has 0 tracks, and has a duration of 0.0 seconds. I checked the url, and it's "assets-library://asset/asset.MOV?id=9F482CF8-B4F6-40C2-A687-0D05F5F25529&ext=MOV" which seems correct. I know alAsset is actually a video, and the correct video, because I've displayed alAsset.thumbnail, and it's shown the correct thumbnail for the video.
All this leads me to believe there's something going wrong in the initialization for avAsset, but for the life of me, I can't figure out what's going wrong. Can anyone help me?
Update:
I think i've confirmed that the url being given to me by ALAssetRepresentation is faulty, which is weird because it gives me the correct thumbnail. I added this code in:
NSLog([NSString stringWithFormat:#"%i", [url checkResourceIsReachableAndReturnError:&error]]);
NSLog([NSString stringWithFormat:#"%#", error]);
It gives me this:
0
Error Domain=NSCocoaErrorDomain Code=4 "The operation couldn’t be completed. (Cocoa error 4.)" UserInfo=0x19df60 {}
I'm still not sure what would cause that. The only thing I'm noticing is the url, which is "assets-library://asset/asset.MOV?id=9F482CF8-B4F6-40C2-A687-0D05F5F25529&ext=MOV" is different from what I've seen as I've been searching around for this. The one i've seen elsewhere looks more like "assets-library://asset/asset.MOV?id=1000000394&ext=MOV", with a number instead of an alphanumeric, dash separated name.
If it helps, I'm using XCode 4.2 Beta, and iOS5. Please let me know if you can think of anything. Thanks.
Okay, looks like it was a bug in the iOS5 beta v1. I upgraded to the newest and it worked. Thanks to those who took a look at my question.

NSDATA writeToFile crashes without a reason

I am downloading images from a url using NSDATA and saving them to local file system using
NSData *dataForStorage = [NSData dataWithData:UIImagePNGRepresentation(img)];
BOOL saveResult=[ dataForStorage writeToFile:jpegFilePath options:NSDataWritingAtomic error:&error];
NSLog(#"Write returned error: %#", [error localizedDescription]);
My app crashes randomly without even giving a message, though some files are saved (again randomly). When I run the app in Debug mode, I frequently see "EXC_BAD_ACCESS" but continuing execution succeeds in saving some of the files.
This code is executed in background from:
[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:arr];
Please suggest.
One of the problems in your code is that your running code in a thread without an autorelease pool but are using functions that would require one. Put the following code into the loadImageInBackground method:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// existing code
[pool drain];
This is probably just one of several problems. For further assistance, we need to see the stack trace of the crash.
Just a wild guess : arr is an autoreleased object, so, sometimes it gets deallocated before your selector gets called. Try using [arr copy] and release it after saving it.
I was having the EXACT same problem, but it turned out that the problem was something else: my URL was getting release prematurely. In the end this is what I did and it worked:
I made this call:
[self performSelectorInBackground:#selector(downloadData:) withObject:nil];
And this is the method:
// URL - (NSString) URL for file
// filePath - (NSString) save location on device
-(void)download:(NSString *)URL
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:URL]];
[data writeToFile:filePath atomically:YES];
[pool release];
}
So I think that your download code is correct, but there is some other variable that is getting deallocated early (possibly your path).
Hope this helps! I know the other answers on this page worked for me.