如何从保存在文档目录中的plist中读取数据并在新视图中将其显示为pdf?

时间:2014-02-26 21:01:37

标签: ios objective-c pdf

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

我使用以下命令在添加视图控制器中保存数据:

// 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 createPlistCopyInDocuments:PLIST_NAME];
    NSString *filePath = [self plistFileDocumentPath:PLIST_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 *)plistFileDocumentPath:(NSString *)plistName
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:plistName];
    return writablePath;
}

- (void)createPlistCopyInDocuments:(NSString *)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控制器中,我读取数据并显示如下:

- (void)viewWillAppear:(BOOL)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 *)plistFileDocumentPath:(NSString *)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"]];

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

这是我如何从那个plist创建pdf。

    - (IBAction)pdfPressed:(id)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:@"Preview", @"Email", nil];
    [actionSheet showInView:self.view];
}

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

其他信息:

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

enter image description here

编辑:

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

    - (IBAction)pdfPressed:(id)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:@"Preview", @"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在文档中保存时的结构。

1 个答案:

答案 0 :(得分:1)

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

- (IBAction)pdfPressed:(id)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:@"Preview", @"Email", nil];
    [actionSheet showInView:self.view];





}

OLD解决方案

   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