PDFDocument writeToURL not working - objective-c

I am working with PDFDocument and PDFView.
I'm able to open a file and display it.
But if I try to save it with a different URL via PDFDocument's "writeToURL:" it doesn't work.
I logged the fileURL in the console, which was exactly the same like I typed in the save-Panel. But it doesn't write the Document to that URL.
I tried the same with a new allocated PDFDocument, which was working like i expected it.
Do I forget about any access-issues?
Here's my code:
NSURL* fileURL = [[NSURL alloc] init];
NSSavePanel* savePanel;
savePanel = [NSSavePanel savePanel];
NSArray* fileTypes = [[NSArray alloc] initWithObjects:#"pdf", nil];
[savePanel setAllowedFileTypes:fileTypes];
if([savePanel runModal] == NSFileHandlingPanelOKButton)
{
fileURL = savePanel.URL;
}
else
{
NSLog(#"failed to save file");
fileURL = nil;
}
[pdfView.document writeToURL:fileURL];
Thanks in advance

Related

UIActivityViewController not showing AirDrop option in iOS11

I have some code that shows an UIAcvityViewController for exporting a custom object from my app, formatted as JSON. This code works fine in previous versions of iOS but now fails it iOS 11. The problem is that when the Activity View Controller displays, it does not display the Airdrop panel or available recipient devices at all. The document is an NSDictionary that is encoded and written to a NSData object and then written to disk and referenced by an NSURL. As I stated, this code worked fine and still works fine in previous versions of iOS. I also have another place where I am using the UIActivityViewController to export an image file, and Airdrop continues to work fine in iOS 11. I am assuming that the issue has to do with the format of the file being exported and referenced by the URL I am referencing in the url key of the ActivityProvider, but I have tried every way of outputting and encoding this object that makes sense. Here is the code I am using:
NSString *textToShare = #"I am sharing this record with you!";
NSURL* url = [self.record exportNoteToURL];
NSMutableArray* activityProviders = [[NSMutableArray alloc]initWithCapacity:0];
NoteRecordActivityProvider *provider = [[NoteRecordActivityProvider alloc] initWithPlaceholderItem:#{#"body":textToShare, #"url":url}];
[activityProviders addObject:provider];
//Initialize the ActivityViewController
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityProviders applicationActivities:applicationActivities];
NSArray *excludeActivities = #[UIActivityTypePostToFacebook,
UIActivityTypePostToTwitter,
UIActivityTypePostToWeibo,
//UIActivityTypeMessage,
//UIActivityTypeMail,
//UIActivityTypePrint,
UIActivityTypeCopyToPasteboard,
UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAddToReadingList,
UIActivityTypePostToFlickr,
UIActivityTypePostToVimeo,
UIActivityTypePostToTencentWeibo,
//UIActivityTypeAirDrop,
UIActivityTypeOpenInIBooks];
activityController.excludedActivityTypes = excludeActivities;
[activityController setValue:[NSString stringWithFormat:#"Record: %#", self.record.title] forKey:#"subject"];
activityController.popoverPresentationController.barButtonItem = (UIBarButtonItem*)sender;
activityController.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
if (completed)
{
NSLog(#"The Activity: %# was completed", activityType);
}
else
{
NSLog(#"The Activity: %# was NOT completed", activityType);
}
[FileSystemProvider clearExportsDirectory];
};
[self presentViewController:activityController animated:YES completion:nil];
Following is the code that exports the dictionary to the URL, which seems to be working properly.
#pragma mark Document Export
-(NSURL*) exportNoteToURL
{
NSMutableDictionary* dict =[[NSMutableDictionary alloc]initWithCapacity:0];
// 1 Create Dictionary
NSDictionary* noteDict = [self getSettingsDictionary];
[dict setValue:noteDict forKey:#"Note"];
// 2 Get File Name and create file path
NSString* fullFilePath = [[FileSystemProvider documentPath]stringByAppendingPathComponent:#"Exports"];
NSLog(#"Export Path: %#", fullFilePath);
[MiscUtilities createDirectory:fullFilePath];
NSString* fileName = #"ExportedNoteRecord.lgz";
fileName = self.title;
fileName = [fileName stringByReplacingOccurrencesOfString:#" " withString:#""];
fileName = [MiscUtilities SanitizeFileNameString:fileName];
fileName = [NSString stringWithFormat:#"%#%#", fileName, #".lgz"];
fullFilePath = [fullFilePath stringByAppendingPathComponent:fileName];
// 3 Write dictionary to FileSystem
NSURL* url = [[NSURL alloc]initFileURLWithPath:fullFilePath];
BOOL res = [dict writeToURL:url error:&error];
if (res)
{
return url;
}
else
{
return nil;
}
}
The problem is that your activityViewControllerPlaceholderItem returns a Dictionary. The type you return here is used as an indication of what type of object you are vending. Airdrop doesn't want to receive a mysterious Dictionary so it doesn't respond. If what are vending is a file URL, you should have been returning a URL.

iCloud Drive - Read & Write (NSData)

Trying to save custom objects as NSData then upload to iCloud Drive
any direction?
I tried already the Key-Value Method, but it is limited for 1MB :/
is it the correct way?
if yes, how can I read from the iCloud path?
+(void)iCloudWrite:(NSData*)data
{
NSURL* ubiq = [[NSFileManager defaultManager]URLForUbiquityContainerIdentifier:nil];
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:#"Documents"] URLByAppendingPathComponent:#"iCloudHistory.zip"];
MyDocument *mydoc = [[MyDocument alloc] initWithFileURL:ubiquitousPackage];
mydoc.dataContent = data;
[mydoc saveToURL:[mydoc fileURL] forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success)
{
if (success)
{
NSLog(#"Synced with icloud");
}
else
NSLog(#"Syncing FAILED with icloud");
}];
}
EDITED:
// 1. Any file can be uploaded to iCloud container of any size (yes you should be having that much of space in iCloud) lets take an example SampleData.zip
// 2. This method will upload or sync SampleData.zip file in iCloud container, iCloud actually checks the metadata of your file before it uploads it into your iCloud container (so for first time it will upload the file and from next time it will only upload the changes)
-(void) iCloudSyncing:(id)sender
{
//Doc dir
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"SampleData.zip"];
NSURL *u = [[NSURL alloc] initFileURLWithPath:filePath];
NSData *data = [[NSData alloc] initWithContentsOfURL:u];
//Get iCloud container URL
NSURL *ubiq = [[NSFileManager defaultManager]URLForUbiquityContainerIdentifier:nil];// in place of nil you can add your container name
//Create Document dir in iCloud container and upload/sync SampleData.zip
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:#"Documents"]URLByAppendingPathComponent:#"SampleData.zip"];
Mydoc = [[MyDocument alloc] initWithFileURL:ubiquitousPackage];
Mydoc.zipDataContent = data;
[Mydoc saveToURL:[Mydoc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success)
{
if (success)
{
NSLog(#"SampleData.zip: Synced with icloud");
}
else
NSLog(#"SampleData.zip: Syncing FAILED with icloud");
}];
}
// 3 Download data from the iCloud Container
- (IBAction)GetData:(id)sender {
//--------------------------Get data back from iCloud -----------------------------//
id token = [[NSFileManager defaultManager] ubiquityIdentityToken];
if (token == nil)
{
NSLog(#"ICloud Is not LogIn");
}
else
{
NSLog(#"ICloud Is LogIn");
NSError *error = nil;
NSURL *ubiq = [[NSFileManager defaultManager]URLForUbiquityContainerIdentifier:nil];// in place of nil you can add your container name
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:#"Documents"]URLByAppendingPathComponent:#"SampleData.zip"];
BOOL isFileDounloaded = [[NSFileManager defaultManager]startDownloadingUbiquitousItemAtURL:ubiquitousPackage error:&error];
if (isFileDounloaded) {
NSLog(#"%d",isFileDounloaded);
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
//changing the file name as SampleData.zip is already present in doc directory which we have used for upload
NSString* fileName = [NSString stringWithFormat:#"RecSampleData.zip"];
NSString* fileAtPath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSData *dataFile = [NSData dataWithContentsOfURL:ubiquitousPackage];
BOOL fileStatus = [dataFile writeToFile:fileAtPath atomically:NO];
if (fileStatus) {
NSLog(#"success");
}
}
else{
NSLog(#"%d",isFileDounloaded);
}
}
}
//4 voila its done :)
Don't forget to add following parameters to your plist
<key>NSUbiquitousContainers</key>
<dict>
<key>YourCloudContainerID</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerName</key>
<string>YourCloudContainerName</string>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>

uiWebView printing a pdf

Inside of uiwebview, what is a good way print a pdf document?
The pdf is accessible via a url or it can be loaded inside of an iframe.
Using the standard javascript widnow.print() functions will not work.
I am considering using a javascript bridge such as:
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *URL = [request URL];
if ([[URL scheme] isEqualToString:#"native"]) {
NSString *urlString = [[request URL] absoluteString];
NSArray *urlParts = [urlString componentsSeparatedByString:#":"];
NSString *cmd = [urlParts objectAtIndex:1];
if ( [cmd isEqualToString:#"printPdf"] ) {
// [self dosomething];
}
}
return YES;
}
At this point I need some sort of xcode function which accept a path to the pdf and send it the airPrinter.
Is this a good approach? I am searching examples of how to print a pdf inside a uiWebView.
As I've earned the tumbleweed badge for no up votes and no responses, I'll post my solution.
This fetches the pdf doc and opens the airPrint dialog--all within a uiWebView.
So if IOS would simply allow the javascript window.print() to function inside of uiWebView, my app would not be setting in the app store waiting for approval and re-release.
Anyway, here's a working solution:
- (void)printInit:(NSString *)parm {
UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];
if(!controller){
NSLog(#"Couldn't get shared UIPrintInteractionController!");
return;
}
NSString *base = #"https://someurl.com/";
NSString *ustr = [base stringByAppendingString:parm];
//NSURL *url = [NSURL fileURLWithPath:ustr];
NSURL *url = [NSURL URLWithString:ustr];
NSData *thePdf = [NSData dataWithContentsOfURL:url];
controller.printingItem = thePdf;
UIPrintInfo *printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGeneral;
printInfo.jobName = #"PDFDoc";
controller.printInfo = printInfo;
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
if (!completed && error) {
NSLog(#"FAILED! error = %#",[error localizedDescription]);
}
};
CGRect rect = CGRectMake(310, 5, 100, 5);
[controller presentFromRect:rect inView:self.webView animated:YES completionHandler:completionHandler];
}

Vfr-Reader crashes on assert(range.location != NSNotFound);

I am using thisopen source control called Vfr Reader to show pdf files in my app. All was working on iOS 7. After iOS update app crashes when I try on open a pdf file.
I am using this code to initialize pdf reader.
NSString *fileName = [[NSBundle mainBundle] pathForResource:#"PdfName" ofType:#"pdf"];
ReaderDocument *document = [ReaderDocument withDocumentFilePath:fileName password:nil];
if (document != nil)
{
ReaderViewController *readerViewController = [[ReaderViewController alloc] initWithReaderDocument:document];
readerViewController.delegate = self;
readerViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
readerViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:readerViewController animated:YES completion:Nil];
}
App crashes in this fuction of vfr
+ (NSString *)relativeFilePath:(NSString *)fullFilePath
{
assert(fullFilePath != nil); // Ensure that the full file path is not nil
NSString *applicationPath = [ReaderDocument applicationPath]; // Get the application path
NSRange range = [fullFilePath rangeOfString:applicationPath]; // Look for the application path
assert(range.location != NSNotFound); // **Crashes here**
return [fullFilePath stringByReplacingCharactersInRange:range withString:#""]; // Strip it out
}
On crash debugger shows these values.
fullFilePath = #"/Users/GuruTraxiOSDev01/Library/Developer/CoreSimulator/Devices/CC9412A6-9A95-4F46-89BA-8ECC13D0AF19/data/Containers/Bundle/Application/D2DC440B-F010-4575-93FD-3CB05BFF4F78/AppName.app/PdfName.pdf" 0x798c9b30
range = location=2147483647, length=0
applicationPath =#"/Users/GuruTraxiOSDev01/Library/Developer/CoreSimulator/Devices/CC9412A6-9A95-4F46-89BA-8ECC13D0AF19/data/Containers/Data/Application/32D612DE-FFD2-4C1E-B403-CDA177B460A6" 0x798b46b0
I already confirmed the file's existence.
Can anyone help please!
EDIT: This question solved crash on file load. But app still crashes on
CGContextDrawPDFPage(context, thePDFPageRef);
I was facing the same issue, so I made some changes to the Library Files which should not be an option as such but in this case I didn't have any choice to get it to work. So to make your code work follow the instruction below:
Go to ReaderDocument.m file and make the following changes:
+ (NSString *)documentsPath
{
//Make changes to return the NSBundle path.
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSFileManager *fileManager = [NSFileManager new]; // File manager instance
NSURL *pathURL = [fileManager URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
// return [pathURL path]; // Path to the application's "~/Documents" directory // Code changes.
return bundlePath;
}
If you had a breakpoint just delete it, that solve it for me.
Breakpoint navigator => select the breakpoint then delete

iOS - How to Save to and Read from file using Archiving?

I'am new to Xcode and I really need help on this.
I'm trying to use Archiving to save a file with an array of items and trying to read and put them in a table view.
The problem is that when I close the app and then launch it again, when I save the data into the file it overwrites the existing file and all the stored data goes away.
I'm using this methods to store data in the file:
-(id)init
{
if(self = [super init])
{
_appSupportPath = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)lastObject];
if (!_appSupportPath)
return nil;
_repositoryPath = [_appSupportPath stringByAppendingPathComponent:FILE_NAME];
if (_data == nil)
_data = [[NSMutableDictionary alloc] init];
}
return self;
}
-(void)saveToFile
{
dispatch_queue_t writeQueue = dispatch_queue_create("MyApp:file:write", NULL);
NSMutableDictionary *localData = [NSMutableDictionary dictionaryWithDictionary:_data];
dispatch_async(writeQueue, ^{
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:_appSupportPath])
[fileManager createDirectoryAtPath:_appSupportPath withIntermediateDirectories:YES attributes:nil error:NULL];
[NSKeyedArchiver archiveRootObject:localData toFile:_repositoryPath];
});
}
Any help?
Please let me know if there's a better/easier way of storing files that I'm not aware of.
Thanks in advance
You save it correctly.
Read it on launch in the init:
_data = [[NSKeyedUnarchiver unarchiveObjectWithFile:_repositoryPath] retain];
if (_data == nil)
_data = [[NSMutableDictionary alloc] init];