IOS Opening PDF from my app in another app EXC_BAD_ACCESS - ios

I'm having difficulty debugging this error. I get an EXC_BAD_ACCESS error after I click on Adobe or Nook as the selected app to open the download PDF. I've gone through with the debugger and it breaks somewhere outside of the methods I wrote. Here is the code in question.
//download protocol
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *storedEmail = [defaults stringForKey:#"email"];
NSString *storedPassword = [defaults stringForKey:#"password"];
NSString *projectID = self.study.ProjectID;
NSString *urlString = [NSString stringWithFormat:#"http://service.pharmatech.com/Document/projectprotocol/%#/%#/%#", storedEmail, storedPassword, projectID];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:url];
if (data) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, [NSString stringWithFormat:#"Protocol_%#.pdf", projectID]];
[data writeToFile:filePath atomically:YES];
UIDocumentInteractionController *docController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
docController.delegate = self;
docController.UTI = #"com.adobe.pdf";
self.navigationController.toolbarHidden = NO;
BOOL isValid = [docController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
NSLog([NSString stringWithFormat:#"DISPLAYED? %d", isValid]);
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:NULL];
for (int count = 0; count < (int)[directoryContent count]; count++) {
NSLog(#"File %d: %#", (count + 1), [directoryContent objectAtIndex:count]);
}
[self.navigationController setToolbarHidden:YES animated:YES];
The popup shows with the apps capable of showing pdfs. After I click one the Bad Access error occurs, but not until after leaving the method this is called in, which is just a button click action.
If I run the app w/o the debugger is simply closes the my app and opens nothing. Anyone have any tips. I'm still very new to this ios stuff.
EDIT: For those who visit this later and don't read the comments, the answer is that the UIDocumentInteractionController must be an instance variable, not local.

It seems to be a problem with "docController", is a local variable and, i think, must be a instance variable.
Change
UIDocumentInteractionController *docController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
for
docController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
and in your .h declare
UIDocumentInteractionController *docController;

Related

Saving and viewing files in iOS

I'm getting base64-encoded file content from server. Then I'm writing data into file. I checked that file is not empty after that, it means data was successfully written to file. But when I'm trying to present this file, all I get is an empty view. So what am I doin' wrong?
enter image description here
[f getFile:^(NSString * _Nonnull string) {
NSString *docsDir;
NSArray *dirPaths;
NSData *content = [string dataUsingEncoding:NSUTF8StringEncoding];
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:#"hill.jpg"]];
[content writeToFile:databasePath atomically:YES];
if ([[NSFileManager defaultManager] fileExistsAtPath:databasePath]){
NSURL *url = [NSURL fileURLWithPath:databasePath];
UIDocumentInteractionController *documentInteractionController =[UIDocumentInteractionController interactionControllerWithURL:url];
documentInteractionController.delegate = self;
[documentInteractionController presentPreviewAnimated:YES];
}
} Error:^(NSString * _Nonnull errorMessage) {
}];
Edited your code snippet, Try it
[f getFile:^(NSString * _Nonnull string) {
NSString *docsDir;
NSArray *dirPaths;
NSData *content = [[NSData alloc] initWithBase64EncodedString: string options:0];
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:#"hill.jpg"]];
[content writeToFile:databasePath atomically:YES];
if ([[NSFileManager defaultManager] fileExistsAtPath:databasePath]){
NSURL *url = [NSURL fileURLWithPath:databasePath];
UIDocumentInteractionController *documentInteractionController =[UIDocumentInteractionController interactionControllerWithURL:url];
documentInteractionController.delegate = self;
[documentInteractionController presentPreviewAnimated:YES];
}
} Error:^(NSString * _Nonnull errorMessage) {
}];
From your code, I see you save a string into a an image file (hill.jpg). The UIDocumentInteractionController read file base on their extension, so they can't read this file. I think if you change your file name to hill.txt, your code could work. Hope this helps.
As you say, the content gets from the server are base64-encode, so you need to decode it.
NSData *imageContent = [[NSData alloc] initWithBase64EncodedString:string options:kNilOptions];
if (imageContent) {
// save to file
}

Objective-C Download file and use it with Document Interaction Controller

I have this code here, that is incomplete. The First part downloads a file from a URL:
NSString *stringURL = #"http://www.example.com/pdf/035.pdf";
NSURL *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url];
if ( urlData )
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"035.pdf"];
[urlData writeToFile:filePath atomically:YES];
}
and puts it in: var/mobile/Containers/Data/Application/
Now I want to use this download file with Document Interaction Controller like so:
NSURL *URL = [[NSBundle mainBundle] URLForResource:#"035" withExtension:#"pdf"];
if (URL) {
// Initialize Document Interaction Controller
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:URL];
// Configure Document Interaction Controller
[self.documentInteractionController setDelegate:self];
// Preview PDF
[self.documentInteractionController presentPreviewAnimated:YES];
}
How would I get the file from var/mobile/Containers/Data/Application/ and display it using Document Interaction Controller ?

UIDocumentInteractionController "invalid scheme (null)"

I'm trying to preview a document with UIDocumentInteractionController.
The document is an .xls file which my app downloads from the web. I keep getting this error:
'UIDocumentInteractionController: invalid scheme (null). Only the file scheme is supported.'
I use the next code:
- (void) webServiceController:(WebServiceController *)webServiceController returnedArray:(NSMutableArray *)array {
if ([webServiceController.webRequest isEqualToString: #"generateExcelFileForEmployee"]) {
// start previewing the document at the current section index
NSString *link = [[NSString stringWithString:array[0]] stringByReplacingOccurrencesOfString:#"AdminFunctions.php" withString:#"AdminFunctions.xls"];
link = [[[link stringByReplacingOccurrencesOfString:#"\\" withString:#""]stringByReplacingOccurrencesOfString:#"/public/sites/" withString:#"http://"]stringByReplacingOccurrencesOfString:#"\"\\\"" withString:#""];
NSLog(#"%#", link);
NSData *urlData = [NSData dataWithContentsOfURL:[NSURL URLWithString:link]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"AdminFunctions.xls"];
BOOL isWriteSuccess = [urlData writeToFile:filePath atomically:YES];
NSLog(#"%#", filePath);
if(isWriteSuccess) //success
{
file = [NSURL fileURLWithPath:filePath];
self.fileView = [self setupControllerWithURL:file usingDelegate:self];
[self.fileView presentPreviewAnimated:YES];
}
else
{
NSLog(#"file not written");
}
}
}
- (UIDocumentInteractionController *) setupControllerWithURL: (NSURL*) fileURL usingDelegate: (id <UIDocumentInteractionControllerDelegate>) interactionDelegate {
UIDocumentInteractionController *interactionController =
[UIDocumentInteractionController interactionControllerWithURL: fileURL];
interactionController.delegate = interactionDelegate;
return interactionController;
}
- (UIViewController *) documentInteractionControllerViewControllerForPreview: (UIDocumentInteractionController *) controller {
return self;
}
Both methods are implemented in the viewcontroller in which I want to present the preview. I know by hard i'm getting the data in the urlData object, because when I put in breakpoints, the console says that it contains 6144 bytes, which is exactly the size of the document to download.
I have been looking for this for quiet a while now, but I can't seem to figure out how to solve this. I already tried putting in the link object as a source for the documentInteractionController, but then the error changes to:
'UIDocumentInteractionController: invalid scheme (http). Only the file scheme is supported.'
Any comments on how I can overcome this issue would be highly appreciated
Try to use
// objC
file = [NSURL fileURLWithPath:filePath];
// swift
file = URL.init(fileURLWithPath: filePath)
instead of
//objC
file = [NSURL URLWithString:filePath];
// swift
file = URL.init(string: filePath)

Sharing photo to Instagram

I'm trying to share a photo to Instagram. So far my method is like this:
- (void)shareToInsta:(UIImage *)finalImage
{
NSString *savePath = [NSHomeDirectory() stringByAppendingString:#"Documents/instagramTmp.igo"];
[UIImageJPEGRepresentation(finalImage, 1.0) writeToFile:savePath atomically:YES];
_documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:savePath]];
_documentInteractionController.UTI = #"com.instagram.exclusivegram";
_documentInteractionController.delegate = self;
[_documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
}
The Instagram option is presented in UIDocumentInteractionController, but when I choose it, nothing happens. Anyone knows what I'm doing wrong?
PS: I'm already using a method just like this, but for WhatsApp, and it works just fine.
Save the file is wrong
- (void) saveimage:(UIImage*)image
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"save.igo"];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
}
and
NSString *jpgPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/save.igo"];
NSURL *igImageHookFile = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"file://%#", jpgPath]];

How do I load a CSV in IOS after saving it locally

I have a CSV file that I'm downloading from an S3 account and I would like to show it in my ios app by using the Quicklook framework.
The error I'm getting is in my console. It says
QLPreviewController's datasource shouldn't be nil at this point.
This appears after this line of code runs // Set data source
[previewer setDataSource:self];
here's all the code for downloading the file, saving it and then loading with quicklook
-(void)showDocument
{
NSString *stringURL = #"http://jornada.s3.amazonaws.com/Dust.csv";
NSURL *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:nil];
if ( urlData )
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"tempfile.csv"];
//[urlData writeToFile:filePath atomically:YES];
BOOL newFile = [[NSFileManager defaultManager] createFileAtPath:filePath contents:urlData attributes:nil];
arrayOfDocuments = [[NSArray alloc] initWithObjects:
filePath, nil];
QLPreviewController *previewer = [[QLPreviewController alloc] init];
[self addSubview:previewer.view];
// Set data source
[previewer setDataSource:self];
// Which item to preview
[previewer setCurrentPreviewItemIndex:0];
}
}
/*---------------------------------------------------------------------------
*
*--------------------------------------------------------------------------*/
- (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller
{
return [arrayOfDocuments count];
}
/*---------------------------------------------------------------------------
*
*--------------------------------------------------------------------------*/
- (id <QLPreviewItem>)previewController: (QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
// Break the path into it's components (filename and extension)
NSArray *fileComponents = [[arrayOfDocuments objectAtIndex: index] componentsSeparatedByString:#"."];
NSArray *filePaths = [[fileComponents objectAtIndex:0] componentsSeparatedByString:#"/"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:[((NSString *)[filePaths objectAtIndex:[filePaths count]-1]) stringByAppendingString:(NSString*)[fileComponents objectAtIndex:1]]];
// Use the filename (index 0) and the extension (index 1) to get path
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
if (fileExists) {
//
}
return [NSURL fileURLWithPath:filePath isDirectory:NO];
}
You don't add a preview controller's view to your view - you present the preview controller. And you should do that after setting the data source! So, in this order:
QLPreviewController* preview = [QLPreviewController new];
preview.dataSource = self;
[self presentViewController:preview animated:YES completion:nil];

Resources