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

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

Related

Downloading From Parse on Apple TV

The bounty expires in 3 days. Answers to this question are eligible for a +500 reputation bounty.
user717452 wants to draw more attention to this question.
I have a parse server set up, and as part of it, small PDFs (425KB) are stored on it. I need my Apple TV to be able to display these, but since they change often, it has to come from Parse server, and not just the main bundle where I update it with each update of the app. The issue I'm running into is the lack of an NSDocumentsDirectory on the Apple TV. How do y'all handle this? I've been using the Cache directory, but it seems to only work half the time with the code I am currently using. If I run it at launch from AppDelegate, by the time the PDF is needed, it may not be there, and if I have it set to run this code right when I need it, there is a delay, and sometimes, it simply doesn't show up. Would using NSTemporaryDirectory() be better? UPDATE, no, it doesn't. Works fine on simulator, on Apple TV, have to run the code two times to get it to both download, and draw the PDF
-(void)sermonTime {
//Check if PFFile exists, if so, display PDF, if not, blank time.
if ([self.entry[#"SermonPresIncluded"] isEqualToString:#"NO"]) {
[self blankTime];
}
else {
NSLog(#"SermonTime");
PFFileObject *thumbnail = self.entry[#"SermonPDF"];
[thumbnail getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [[documentsDirectory stringByAppendingPathComponent:[self.entry valueForKey:#"DateOfService"]] stringByAppendingString:#".pdf"];
[imageData writeToFile:pdfPath atomically:YES];
NSURL *url = [NSURL fileURLWithPath:pdfPath];
self.view.backgroundColor = [UIColor blackColor];
self.arrayOfVerses = #[#"allverses"];
CGPDFDocumentRef pdfDocument = [self openPDF:url];
[self drawDocument:pdfDocument];
}];
}
}
-(void)sermonTime {
// Check if PFFile exists, if so, display PDF, if not, blank time.
if ([self.entry[#"SermonPresIncluded"] isEqualToString:#"NO"]) {
[self blankTime];
}
else {
NSLog(#"SermonTime");
PFFileObject *thumbnail = self.entry[#"SermonPDF"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [[documentsDirectory stringByAppendingPathComponent:[self.entry valueForKey:#"DateOfService"]] stringByAppendingString:#".pdf"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:pdfPath]) {
// Use cached copy of PDF
NSURL *url = [NSURL fileURLWithPath:pdfPath];
self.view.backgroundColor = [UIColor blackColor];
self.arrayOfVerses = #[#"allverses"];
CGPDFDocumentRef pdfDocument = [self openPDF:url];
[self drawDocument:pdfDocument];
} else {
// Download and save the PDF
[thumbnail getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (error) {
// Handle the error
NSLog(#"Error downloading PDF: %#", error);
[self blankTime];
} else {
[imageData writeToFile:pdfPath atomically:YES];
// Use completion block to signal that the PDF is ready to display
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = [NSURL fileURLWithPath:pdfPath];
self.view.backgroundColor = [UIColor blackColor];
self.arrayOfVerses = #[#"allverses"];
CGPDFDocumentRef pdfDocument = [self openPDF:url];
[self drawDocument:pdfDocument];
});
}
}];
}
}
}
Made some changes to the code.
It will first check if the PDF exists cache, it will use the PDF if it exists in cache and will only proceed download if it does not exists. Then, to make sure that PDF is downloaded and saved successfully you can use a completion block. With completion block, it will only proceed to draw it when the block is called to avoid the PDF does't show up.

Read file in document failed in Xcode 11.3

When I read file in document using stringWithContentsOfURL it failed
this is error in Xcode console:
Error Domain=NSCocoaErrorDomain Code=256 "The file “1.txt” couldn’t be opened." UserInfo={NSURL=/var/mobile/Containers/Data/Application/E026973D-11B6-4895-B8FE-7F9FBCC11C12/Documents/bbbb/1.txt}
this is my code:
//use objective-c
+(NSString * )loadDataFromDocumentDirectory:(NSString *)path andSubDirectory:(NSString *)subdirectory {
path = [self stripSlashIfNeeded:path];
subdirectory = [self stripSlashIfNeeded:subdirectory];
// Create generic beginning to file save path
NSMutableString *savePath = [[NSMutableString alloc] initWithFormat:#"%#/",[self applicationDocumentsDirectory].path];
[savePath appendString:subdirectory];
[savePath appendString:#"/"];
// Add requested save path
NSError *err = nil;
[savePath appendString:path];
NSURL *fileURL = [NSURL URLWithString:savePath];
NSString *loadStr = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&err] ;
if (err) NSLog(#"load error : %#", err);
return loadStr;
}
//use swift
let loadData = FileSave.loadData(fromDocumentDirectory: "1.txt", andSubDirectory: "bbbb")
You are using the wrong API:
URLWithString is for URLs including the scheme (file:// or https://), for file system paths you have to use fileURLWithPath.
However it's highly recommended to use always the URL related API to build paths
+ (NSString * )loadDataFromDocumentDirectory:(NSString *)path andSubDirectory:(NSString *)subdirectory {
// path = [self stripSlashIfNeeded:path]; not needed
// subdirectory = [self stripSlashIfNeeded:subdirectory]; not needed
// Create generic beginning to file save path
NSURL *saveURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:subdirectory];
// Add requested save path
NSError *err = nil;
NSURL *fileURL = [saveURL URLByAppendingPathComponent:path];
NSString *loadStr = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&err] ;
if (err) NSLog(#"load error : %#", err);
return loadStr;
}

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.

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];

PDFDocument writeToURL not working

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