OStack程序员社区-中国程序员成长平台

标题: ios - 如何从保存在文档目录中的 plist 中读取数据并在新 View 中将其显示为 pdf? [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-12 19:31
标题: ios - 如何从保存在文档目录中的 plist 中读取数据并在新 View 中将其显示为 pdf?

因此,我将用户输入数据保存在文档目录中的 plist 中。数据由几个字符串组成。比如文字和图片。用户通过文本字段在添加 View 中输入数据,通过相机或相册输入图像。

我使用以下方法将数据保存在添加 View Controller 中:

// Name for the image
    NSString *imageName;

    if (self.image) {
        // Create a unique name for the image by generating a UUID, converting it to
        // a string, and appending the .jpg extension.
        CFUUIDRef imageUUID = CFUUIDCreate(kCFAllocatorDefault);
        imageName = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, imageUUID));
        CFRelease(imageUUID);
        imageName = [imageName stringByAppendingString".jpg"];

        // Lookup the URL for the Documents folder
        NSURL *imageFileURL = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0];
        // Append the file name to create the complete URL for saving the image.
        imageFileURL = [imageFileURL URLByAppendingPathComponent:imageName isDirectory:NO];

        // Convert the image to JPG format and write the data to disk at the above URL.
        [UIImageJPEGRepresentation(self.image, 1.0f) writeToURL:imageFileURL atomically:YES];
    } else {
        // If there is no image, we must make sure imageName is not nil.
        imageName = @"";
    }
#define PLIST_NAME @"Data.plist"
    [self createPlistCopyInDocumentsLIST_NAME];
    NSString *filePath = [self plistFileDocumentPathLIST_NAME];
    NSMutableArray *dataArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
    NSDictionary *data = @{@"city":self.name,@"state":self.stateTextField.text,@"cityPrice":self.priceTextField.text,@"cityText":self.cityDescription.text, @"cityImage": imageName};
    [dataArray addObject:data];
    [dataArray writeToFile:filePath atomically:YES];

然后我为文档路径添加以下方法:

- (NSString *)plistFileDocumentPathNSString *)plistName
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:plistName];
    return writablePath;
}

- (void)createPlistCopyInDocumentsNSString *)plistName
{
    // First, test for existence.
    BOOL success;

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;
    NSString *plistFilePath = [self plistFileDocumentPath:plistName];
    success = [fileManager fileExistsAtPath:plistFilePath];

    if (success) {
        return;
    }

    // The writable file does not exist, so copy from the bundle to the appropriate location.
    NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:plistName];
    success = [fileManager copyItemAtPath:defaultPath toPath:plistFilePath error:&error];
    if (!success) {
        NSAssert1(0, @"Failed to create writable file with message '%@'.", [error localizedDescription]);
    }
}

然后在我的 tableview Controller 中读取数据并显示如下:

- (void)viewWillAppearBOOL)animated
{
    [super viewWillAppear:animated];
    NSString *filePath = [self plistFileDocumentPath"Data.plist"];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL exist = [fileManager fileExistsAtPath:filePath];
    if (!exist) {
        return;
    }
    NSMutableArray *dataArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
    content = dataArray;
    [self.tableView reloadData];
}

- (NSString *)plistFileDocumentPathNSString *)plistName
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:plistName];
    return writablePath;
}

我确实看到了 plist 确实加载如下:

content = [[NSMutableArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource"Data" ofType"plist"]];

我还可以在我的详细 View 中正确显示所有信息。我创建了一个新 View ,以便将 plist 中保存的数据显示为 pdf 文件。我能够从我目录中的现有 plist 中检索数据,但我无法转换该代码以从我保存的 plist 中读取数据。

这就是我从该 plist 创建 pdf 的方式。

    - (IBAction)pdfPressedid)sender {


    // create some sample data. In a real application, this would come from the database or an API.
    NSString* path = [[NSBundle mainBundle] pathForResource"sampleData" ofType"plist"];
    NSDictionary* data = [NSDictionary dictionaryWithContentsOfFile:path];
    NSArray* students = [data objectForKey"Students"];

    // get a temprorary filename for this PDF
    path = NSTemporaryDirectory();
    self.pdfFilePath = [path stringByAppendingPathComponent:[NSString stringWithFormat"%f.pdf", [[NSDate date] timeIntervalSince1970] ]];

    // Create the PDF context using the default page size of 612 x 792.
    // This default is spelled out in the iOS documentation for UIGraphicsBeginPDFContextToFile
    UIGraphicsBeginPDFContextToFile(self.pdfFilePath, CGRectZero, nil);

    // get the context reference so we can render to it.
    CGContextRef context = UIGraphicsGetCurrentContext();

    int currentPage = 0;

    // maximum height and width of the content on the page, byt taking margins into account.
    CGFloat maxWidth = kDefaultPageWidth - kMargin * 2;
    CGFloat maxHeight = kDefaultPageHeight - kMargin * 2;

    // we're going to cap the name of the class to using half of the horizontal page, which is why we're dividing by 2
    CGFloat classNameMaxWidth = maxWidth / 2;

    // the max width of the grade is also half, minus the margin
    CGFloat gradeMaxWidth = (maxWidth / 2) - kColumnMargin;


    // only create the fonts once since it is a somewhat expensive operation
    UIFont* studentNameFont = [UIFont boldSystemFontOfSize:17];
    UIFont* classFont = [UIFont systemFontOfSize:15];

    CGFloat currentPageY = 0;

    // iterate through out students, adding to the pdf each time.
    for (NSDictionary* student in students)
    {
        // every student gets their own page
        // Mark the beginning of a new page.
        UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
        currentPageY = kMargin;

        // draw the student's name at the top of the page.
        NSString* name = [NSString stringWithFormat"%@ %@",
                          [student objectForKey"FirstName"],
                          [student objectForKey:@"LastName"]];

        CGSize size = [name sizeWithFont:studentNameFont forWidth:maxWidth lineBreakMode:NSLineBreakByWordWrapping];
        [name drawAtPoint:CGPointMake(kMargin, currentPageY) forWidth:maxWidth withFont:studentNameFont lineBreakMode:NSLineBreakByWordWrapping];
        currentPageY += size.height;

        // draw a one pixel line under the student's name
        CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]);
        CGContextMoveToPoint(context, kMargin, currentPageY);
        CGContextAddLineToPoint(context, kDefaultPageWidth - kMargin, currentPageY);
        CGContextStrokePath(context);

        // iterate through the list of classes and add these to the PDF.
        NSArray* classes = [student objectForKey:@"Classes"];
        for(NSDictionary* class in classes)
        {
            NSString* className = [class objectForKey:@"Name"];
            NSString* grade = [class objectForKey:@"Grade"];

            // before we render any text to the PDF, we need to measure it, so we'll know where to render the
            // next line.
            size = [className sizeWithFont:classFont constrainedToSize:CGSizeMake(classNameMaxWidth, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];

            // if the current text would render beyond the bounds of the page,
            // start a new page and render it there instead
            if (size.height + currentPageY > maxHeight) {
                // create a new page and reset the current page's Y value
                UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
                currentPageY = kMargin;
            }

            // render the text
            [className drawInRect:CGRectMake(kMargin, currentPageY, classNameMaxWidth, maxHeight) withFont:classFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];

            // print the grade to the right of the class name
            [grade drawInRect:CGRectMake(kMargin + classNameMaxWidth + kColumnMargin, currentPageY, gradeMaxWidth, maxHeight) withFont:classFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];

            currentPageY += size.height;

        }


        // increment the page number.
        currentPage++;

    }

    // end and save the PDF.
    UIGraphicsEndPDFContext();

    // Ask the user if they'd like to see the file or email it.
    UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle:@"Would you like to preview or email this PDF?"
                                                              delegate:self
                                                     cancelButtonTitle:@"Cancel"
                                                destructiveButtonTitle:nil
                                                     otherButtonTitles:@"review", @"Email", nil];
    [actionSheet showInView:self.view];
}

有人可以查看上面给出的信息并帮助我更改此创建 pdf 代码以读取我保存到文档目录中 plist 的数据。这是 github 中演示项目的链接,供任何想要伸出援助之手的人使用。

附加信息:

我将用户输入数据保存在 plist 中,根是一个数组。我用来呈现 PDF 文件的代码来自根是字典的 plist。我需要帮助更改 pdfpressed 中的代码以读取 plist 根将是一个数组而不是字典。

enter image description here

编辑:

我使用了发布的修复程序,整个方法现在看起来像这样:

    - (IBAction)pdfPressedid)sender {

     NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory ,NSUserDomainMask, YES);
     NSString *documentsDirectory = [sysPaths objectAtIndex:0];
     NSString *filePath =  [documentsDirectory stringByAppendingPathComponent:@"Data1.plist"];

     NSLog(@"File Path: %@", filePath);

     NSArray *students = [NSArray arrayWithContentsOfFile:filePath];

    // get a temprorary filename for this PDF
    filePath = NSTemporaryDirectory();
    self.pdfFilePath = [filePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%f.pdf", [[NSDate date] timeIntervalSince1970] ]];

    // Create the PDF context using the default page size of 612 x 792.
    // This default is spelled out in the iOS documentation for UIGraphicsBeginPDFContextToFile
    UIGraphicsBeginPDFContextToFile(self.pdfFilePath, CGRectZero, nil);

    // get the context reference so we can render to it.
    CGContextRef context = UIGraphicsGetCurrentContext();

    int currentPage = 0;

    // maximum height and width of the content on the page, byt taking margins into account.
    CGFloat maxWidth = kDefaultPageWidth - kMargin * 2;
    CGFloat maxHeight = kDefaultPageHeight - kMargin * 2;

    // we're going to cap the name of the class to using half of the horizontal page, which is why we're dividing by 2
    CGFloat classNameMaxWidth = maxWidth / 2;

    // the max width of the grade is also half, minus the margin
    CGFloat gradeMaxWidth = (maxWidth / 2) - kColumnMargin;


    // only create the fonts once since it is a somewhat expensive operation
    UIFont* studentNameFont = [UIFont boldSystemFontOfSize:17];
    UIFont* classFont = [UIFont systemFontOfSize:15];

    CGFloat currentPageY = 0;

    // iterate through out students, adding to the pdf each time.
    for (NSDictionary* student in students)
    {
        // every student gets their own page
        // Mark the beginning of a new page.
        UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
        currentPageY = kMargin;

        // draw the student's name at the top of the page.
        NSString* name = [NSString stringWithFormat:@"%@ %@ %@ %@", [student valueForKey:@"city"], [student valueForKey:@"state"],[student valueForKey:@"cityPrice"],[student valueForKey:@"cityText"]];

        CGSize size = [name sizeWithFont:studentNameFont forWidth:maxWidth lineBreakMode:NSLineBreakByWordWrapping];
        [name drawAtPoint:CGPointMake(kMargin, currentPageY) forWidth:maxWidth withFont:studentNameFont lineBreakMode:NSLineBreakByWordWrapping];
        currentPageY += size.height;

        // draw a one pixel line under the student's name
        CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]);
        CGContextMoveToPoint(context, kMargin, currentPageY);
        CGContextAddLineToPoint(context, kDefaultPageWidth - kMargin, currentPageY);
        CGContextStrokePath(context);

        // iterate through the list of classes and add these to the PDF.
        NSArray* classes = [student objectForKey:@"Classes"];
        for(NSDictionary* class in classes)
        {
            NSString* className = [class objectForKey:@"Name"];
            NSString* grade = [class objectForKey:@"Grade"];

            // before we render any text to the PDF, we need to measure it, so we'll know where to render the
            // next line.
            size = [className sizeWithFont:classFont constrainedToSize:CGSizeMake(classNameMaxWidth, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];

            // if the current text would render beyond the bounds of the page,
            // start a new page and render it there instead
            if (size.height + currentPageY > maxHeight) {
                // create a new page and reset the current page's Y value
                UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
                currentPageY = kMargin;
            }

            // render the text
            [className drawInRect:CGRectMake(kMargin, currentPageY, classNameMaxWidth, maxHeight) withFont:classFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];

            // print the grade to the right of the class name
            [grade drawInRect:CGRectMake(kMargin + classNameMaxWidth + kColumnMargin, currentPageY, gradeMaxWidth, maxHeight) withFont:classFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];

            currentPageY += size.height;

        }
        // increment the page number.
        currentPage++;
    }

    // end and save the PDF.
    UIGraphicsEndPDFContext();

    // Ask the user if they'd like to see the file or email it.
    UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle:@"Would you like to preview or email this PDF?"
                                                              delegate:self
                                                     cancelButtonTitle:@"Cancel"
                                                destructiveButtonTitle:nil
                                                     otherButtonTitles:@"review", @"Email", nil];
    [actionSheet showInView:self.view];
}

它确实渲染了数据,但它都是作为标题绘制的,并为每个项目创建一个页面。这是屏幕截图

enter image description here

您能帮忙分离信息并让它们出现在一页中吗?

编辑 1:

这是我想要做的:

enter image description here

这是 plist 结构:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <dict>
        <key>city</key>
        <string>asd</string>
        <key>state</key>
        <string>10</string>
        <key>cituPrice</key>
        <string>11</string>
        <key>cityQuantity</key>
        <string>12</string>
        <key>cityVintage</key>
        <string>13</string>
    </dict>
    <dict>
        <key>city</key>
        <string>te2</string>
        <key>state</key>
        <string>1</string>
        <key>cityPrice</key>
        <string>2</string>
        <key>cityQuantity</key>
        <string>3</string>
        <key>cityVintage</key>
        <string>4</string>
    </dict>
    <dict>
        <key>city</key>
        <string>3434</string>
        <key>state</key>
        <string>6</string>
        <key>cityPrice</key>
        <string>7</string>
        <key>cityQuantity</key>
        <string>8</string>
        <key>cityVintage</key>
        <string>9</string>
    </dict>
    <dict>
        <key>city</key>
        <string>test 1</string>
        <key>state</key>
        <string>20</string>
        <key>cityPrice</key>
        <string>30</string>
        <key>cityQuantity</key>
        <string>44</string>
        <key>cityVintage</key>
        <string>55</string>
    </dict>
</array>
</plist>

这就是 plist 保存在文档中时的结构。



Best Answer-推荐答案


更新的解决方案 替换pdfgenerate中的方法

- (IBAction)pdfPressedid)sender {

     NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory ,NSUserDomainMask, YES);
     NSString *documentsDirectory = [sysPaths objectAtIndex:0];
     NSString *filePath =  [documentsDirectory stringByAppendingPathComponent:@"Data.plist"];

     NSLog(@"File Path: %@", filePath);

     NSArray *students = [NSArray arrayWithContentsOfFile:filePath];

    // get a temprorary filename for this PDF
    filePath = NSTemporaryDirectory();
    self.pdfFilePath = [filePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%f.pdf", [[NSDate date] timeIntervalSince1970] ]];

    // Create the PDF context using the default page size of 612 x 792.
    // This default is spelled out in the iOS documentation for UIGraphicsBeginPDFContextToFile
    UIGraphicsBeginPDFContextToFile(self.pdfFilePath, CGRectZero, nil);

    // get the context reference so we can render to it.
    CGContextRef context = UIGraphicsGetCurrentContext();

    int currentPage = 0;

    // maximum height and width of the content on the page, byt taking margins into account.
    CGFloat maxWidth = kDefaultPageWidth - kMargin * 2;
    CGFloat maxHeight = kDefaultPageHeight - kMargin * 2;

    // we're going to cap the name of the class to using half of the horizontal page, which is why we're dividing by 2
    CGFloat classNameMaxWidth = maxWidth / 2;

    // the max width of the grade is also half, minus the margin
    CGFloat gradeMaxWidth = (maxWidth / 2) - kColumnMargin;
    CGFloat grade1MaxWidth = (maxWidth / 2) - kColumnMargin;
    CGFloat grade2MaxWidth = (maxWidth / 2) - kColumnMargin;


    // only create the fonts once since it is a somewhat expensive operation
    UIFont* studentNameFont = [UIFont boldSystemFontOfSize:17];
    UIFont* classFont = [UIFont systemFontOfSize:15];

    CGFloat currentPageY = 0;
    UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
    currentPageY = kMargin;
    // iterate through out students, adding to the pdf each time.
    for (NSDictionary* student in students)
    {
        // every student gets their own page
        // Mark the beginning of a new page.


        // draw the student's name at the top of the page.
        NSString* name = [NSString stringWithFormat:@"%@",
                          [student valueForKey:@"city"]];

        CGSize HeaderSize = [name sizeWithFont:studentNameFont forWidth:maxWidth lineBreakMode:NSLineBreakByWordWrapping];


        // iterate through the list of classes and add these to the PDF.
        //NSArray* classes = [student objectForKey:@"Classes"];

            NSString* className = [student valueForKey:@"state"];
            NSString* grade = [student valueForKey:@"cityPrice"];
            NSString* grade1 = [student valueForKey:@"cityText"];
            NSString* grade2 = [student valueForKey:@"cityQuantity"];

            // before we render any text to the PDF, we need to measure it, so we'll know where to render the
            // next line.
           CGSize DetailSize = [className sizeWithFont:classFont constrainedToSize:CGSizeMake(classNameMaxWidth, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];

            // if the current text would render beyond the bounds of the page,
            // start a new page and render it there instead

        if (HeaderSize.height + DetailSize.height+currentPageY > maxHeight) {
            // create a new page and reset the current page's Y value
            UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
            currentPageY = kMargin;
            currentPage++;
        }
        [name drawAtPoint:CGPointMake(kMargin, currentPageY) forWidth:maxWidth withFont:studentNameFont lineBreakMode:NSLineBreakByWordWrapping];


        // draw a one pixel line under the student's name
        CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]);
        CGContextMoveToPoint(context, kMargin, currentPageY+HeaderSize.height);
        CGContextAddLineToPoint(context, kDefaultPageWidth - kMargin, currentPageY+HeaderSize.height);
        CGContextStrokePath(context);

        // render the text
        [className drawInRect:CGRectMake(kMargin, currentPageY+HeaderSize.height, classNameMaxWidth, maxHeight) withFont:classFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];

        // print the grade to the center of the class name
        [grade drawInRect:CGRectMake (kMargin , currentPageY+HeaderSize.height, gradeMaxWidth, maxHeight) withFont:classFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentCenter];
        // print the grade1 to the right of the class name
        [grade1 drawInRect:CGRectMake(kMargin  , currentPageY+HeaderSize.height, grade1MaxWidth, maxHeight) withFont:classFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentRight];

        [grade2 drawInRect:CGRectMake(kMargin  , currentPageY+HeaderSize.height, grade2MaxWidth, maxHeight) withFont:classFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentRight];
        // increment the page number.
         currentPageY = currentPageY+DetailSize.height+HeaderSize.height+30;

    }

    // end and save the PDF.
    UIGraphicsEndPDFContext();

    // Ask the user if they'd like to see the file or email it.
    UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle:@"Would you like to preview or email this PDF?"
                                                              delegate:self
                                                     cancelButtonTitle:@"Cancel"
                                                destructiveButtonTitle:nil
                                                     otherButtonTitles:@"review", @"Email", nil];
    [actionSheet showInView:self.view];





}

旧解决方案

   NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory ,NSUserDomainMask, YES);
        NSString *documentsDirectory = [sysPaths objectAtIndex:0];
        NSString *filePath =  [documentsDirectory stringByAppendingPathComponent:@"Data1.plist"];

        NSLog(@"File Path: %@", filePath);

       NSArray *students = [NSArray arrayWithContentsOfFile:filePath];

您必须获取特定键的值而不是该键的对象

[student objectForKey:@"city"];

像这样使用它而不是上面的行

[student valueForKey:@"city"];

您将数据存储为数组,以便您可以获取内容数组,上面的代码将帮助您像在 pdfpressed 中一样获取学生变量中的对象数组,您可以继续在其中绘制内容pdf文件。

enter image description here

关于ios - 如何从保存在文档目录中的 plist 中读取数据并在新 View 中将其显示为 pdf?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22053169/






欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) Powered by Discuz! X3.4