【问题标题】:Weird plist behaviour returning null on first value and 13 results when it should be 12奇怪的 plist 行为在第一个值上返回 null ,当它应该是 12 时返回 13 个结果
【发布时间】:2013-05-21 20:56:23
【问题描述】:

在使用 plist 并尝试返回数据时,我遇到了这种奇怪的行为。为了给你一个概述,plist 在每个对象中有 12 个条目,所以我希望有 12 个,但我得到了 13 个,第一个结果是 null 而其余的 12 个实际上是正确的。

这是我的 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">
<dict>
    <key>Name</key>
    <array>
        <string>Audit</string>
        <string>Tax</string>
        <string>Digital</string>
        <string>Consulting</string>
        <string>Risk Advisory</string>
        <string>Finance</string>
        <string>Audit</string>
        <string>Tax</string>
        <string>Digital</string>
        <string>Consulting</string>
        <string>Advisory</string>
        <string>Finance</string>
    </array>
    <key>Logo</key>
    <array>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
        <string>page.png</string>
    </array>
</dict>
</plist>

这是我的 ViewController.h 文件:

#import <UIKit/UIKit.h>
#import "iCarousel.h"


@interface PackViewController : UIViewController <iCarouselDataSource, iCarouselDelegate>
{
    NSMutableArray      *packName;
    NSMutableArray      *packLogo;
}

@property (nonatomic, retain) IBOutlet iCarousel *carousel;
@property (nonatomic, retain) NSMutableArray  *packName;
@property (nonatomic, retain) NSMutableArray  *packLogo;

@end

然后,这是我的 ViewController.m 文件:

#import "PackViewController.h"
#import "AsyncImageView.h"


@interface PackViewController () <UIActionSheetDelegate>

@property (nonatomic, assign) BOOL wrap;
@property (nonatomic, retain) NSMutableArray *items;

@end


@implementation PackViewController

@synthesize carousel, wrap, items;
@synthesize packName, packLogo;

- (void)awakeFromNib
{
    //set up data
    wrap = YES;

    NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"Pack" ofType:@"plist"];
    NSArray *plistItems = [NSDictionary dictionaryWithContentsOfFile:plistPath];
    NSArray *plistData = [plistItems valueForKey:@"Name"];

    self.items = [NSMutableArray array];
    for (int i = 0; i < [plistData count]; i++)
    {
        [items addObject:[NSNumber numberWithInt:i]];
        NSLog(@"First Index Name %@",[items objectAtIndex:i]);
    }
}

- (void)dealloc
{
    carousel.delegate = nil;
    carousel.dataSource = nil;

    [carousel release];
    [super dealloc];
}

#pragma mark -
#pragma mark View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Pack.plist code
    // get paths from root direcory
    NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
    // get documents path
    NSString *documentsPath = [paths objectAtIndex:0];
    // get the path to our Pack.plist file
    NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"Pack.plist"];

    // check to see if Pack.plist exists in documents
    if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
    {
        // if not in documents, get property list from main bundle
        plistPath = [[NSBundle mainBundle] pathForResource:@"Pack" ofType:@"plist"];
    }

    // read property list into memory as an NSData object
    NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
    NSString *errorDesc = nil;
    NSPropertyListFormat format;
    // convert static property list into dictionary object
    NSDictionary *temp = (NSDictionary *)[NSPropertyListSerialization
                                          propertyListFromData:plistXML
                                          mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                          format:&format
                                          errorDescription:&errorDesc];
    if (!temp)
    {
        NSLog(@"Error reading plist: %@, format: %d", errorDesc, format);
    }
    // assign values
    self.packName = [NSMutableArray arrayWithArray:[temp objectForKey:@"Name"]];
    self.packLogo = [NSMutableArray arrayWithArray:[temp objectForKey:@"Logo"]];

    // configure carousel
    carousel.type = iCarouselTypeInvertedWheel;
    carousel.vertical = true;
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.carousel = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

#pragma mark -
#pragma mark UIActionSheet methods

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (buttonIndex >= 0)
    {
        //map button index to carousel type
        iCarouselType type = buttonIndex;

        //carousel can smoothly animate between types
        [UIView beginAnimations:nil context:nil];
        carousel.type = type;
        [UIView commitAnimations];
    }
}

#pragma mark -
#pragma mark iCarousel methods

- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
    //NSLog(@"numberOfItemsInCarousel count: %i", [items count]);
    return [items count];
}

- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
    UIButton *button = (UIButton *)view;
    UILabel *label = nil;

    if (button == nil)
    {
        //no button available to recycle, so create new one
        UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%@", [packLogo objectAtIndex:index]]];
        //NSLog(@"companyLogo: %@", [packLogo objectAtIndex:index]);
        button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height);
        [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [button setBackgroundImage:image forState:UIControlStateNormal];
        button.titleLabel.font = [button.titleLabel.font fontWithSize:20];
        [button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];

        label = [[[UILabel alloc] initWithFrame:view.bounds] autorelease];
        label.backgroundColor = [UIColor clearColor];
        label.textAlignment = UITextAlignmentCenter;
    }
    else
    {
        //get a reference to the label in the recycled view
        label = (UILabel *)[view viewWithTag:1];
    }
    //set button label
    [button setTitle:[self.packName objectAtIndex:index] forState:UIControlStateNormal];
    NSLog(@"companyName: %@", [items objectAtIndex:index]);

    return button;
}

#pragma mark -
#pragma mark item tap event

- (void)buttonTapped:(UIButton *)sender
{
    //get item index for button
    NSInteger index = [carousel indexOfItemViewOrSubview:sender];

    [[[[UIAlertView alloc] initWithTitle:@"Button Tapped"
                                 message:[NSString stringWithFormat:@"You tapped button number %i", index]
                                delegate:nil
                       cancelButtonTitle:@"OK"
                       otherButtonTitles:nil] autorelease] show];
}

- (CATransform3D)carousel:(iCarousel *)_carousel itemTransformForOffset:(CGFloat)offset baseTransform:(CATransform3D)transform
{
    CGFloat count = _carousel.numberOfVisibleItems;
    CGFloat spacing = 1.0f;
    CGFloat arc = M_PI * 2.0f;
    CGFloat radius = _carousel.itemWidth * spacing * count / arc;
    CGFloat angle = arc / count * offset;

    return CATransform3DTranslate(transform, radius - radius * cos(angle), radius * sin(angle), 0.0f);
}

- (CGFloat)carousel:(iCarousel *)_carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value
{
    //customise carousel display
    switch (option)
    {
        case iCarouselOptionWrap:
        {
            //normally you would hard-code this to YES or NO
            return wrap;
        }
        case iCarouselOptionSpacing:
        {
            //add a bit of spacing between the item views
            return value * 1.05f;
        }
        case iCarouselOptionFadeMax:
        {
            if (carousel.type == iCarouselTypeCustom)
            {
                //set opacity based on distance from camera
                return 0.0f;
            }
            return value;
        }
        default:
        {
            return value;
        }
    }
}

@end

您可以看到我的 M 文件中有两行代码输出两个 NSLog 项。它们是:

NSLog(@"First Index Name %@",[items objectAtIndex:i]);
NSLog(@"companyName: %@", [items objectAtIndex:index]);

awakeFromNib 中 for 循环中包含的“第一个索引名称”的输出是:

2013-05-21 22:43:23.875 Pack[7496:c07] First Index Name 0
2013-05-21 22:43:23.877 Pack[7496:c07] First Index Name 1
2013-05-21 22:43:23.878 Pack[7496:c07] First Index Name 2
2013-05-21 22:43:23.879 Pack[7496:c07] First Index Name 3
2013-05-21 22:43:23.880 Pack[7496:c07] First Index Name 4
2013-05-21 22:43:23.880 Pack[7496:c07] First Index Name 5
2013-05-21 22:43:23.881 Pack[7496:c07] First Index Name 6
2013-05-21 22:43:23.881 Pack[7496:c07] First Index Name 7
2013-05-21 22:43:23.882 Pack[7496:c07] First Index Name 8
2013-05-21 22:43:23.882 Pack[7496:c07] First Index Name 9
2013-05-21 22:43:23.883 Pack[7496:c07] First Index Name 10
2013-05-21 22:43:23.883 Pack[7496:c07] First Index Name 11

如您所见,我以正确的顺序获得了所有 12 个值,这是我对第二个值的期望,但这就是问题所在。对于包含在 -(UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view 中的第二个 NSLog我输出items 数组只是为了看看发生了什么。这是我看到的:

2013-05-21 22:43:23.916 Pack[7496:c07] companyName: 0
2013-05-21 22:43:23.918 Pack[7496:c07] companyName: 0
2013-05-21 22:43:23.919 Pack[7496:c07] companyName: 11
2013-05-21 22:43:23.920 Pack[7496:c07] companyName: 7
2013-05-21 22:43:23.921 Pack[7496:c07] companyName: 6
2013-05-21 22:43:23.922 Pack[7496:c07] companyName: 2
2013-05-21 22:43:23.922 Pack[7496:c07] companyName: 1
2013-05-21 22:43:23.923 Pack[7496:c07] companyName: 10
2013-05-21 22:43:23.924 Pack[7496:c07] companyName: 9
2013-05-21 22:43:23.925 Pack[7496:c07] companyName: 8
2013-05-21 22:43:23.925 Pack[7496:c07] companyName: 5
2013-05-21 22:43:23.926 Pack[7496:c07] companyName: 4
2013-05-21 22:43:23.927 Pack[7496:c07] companyName: 3

同样,前两个结果都是0,与第一次迭代不同,排序非常混乱。我found a thread on SO 提到 plist 不一定按顺序输出,因为它们只是关键对象,所以我明白了,但核心问题是前两个结果。

如果我将我的 NSLog 更改为输出 self.packName 的结果(如下所示:NSLog(@"companyName: %@", [self.packName objectAtIndex:index]);),返回的内容如下:

2013-05-21 22:49:43.663 Pack[7543:c07] companyName: (null)
2013-05-21 22:49:43.665 Pack[7543:c07] companyName: Audit
2013-05-21 22:49:43.666 Pack[7543:c07] companyName: Finance
2013-05-21 22:49:43.667 Pack[7543:c07] companyName: Tax
2013-05-21 22:49:43.668 Pack[7543:c07] companyName: Audit
2013-05-21 22:49:43.669 Pack[7543:c07] companyName: Digital
2013-05-21 22:49:43.669 Pack[7543:c07] companyName: Tax
2013-05-21 22:49:43.670 Pack[7543:c07] companyName: Risk Advisory
2013-05-21 22:49:43.671 Pack[7543:c07] companyName: Consulting
2013-05-21 22:49:43.672 Pack[7543:c07] companyName: Digital
2013-05-21 22:49:43.672 Pack[7543:c07] companyName: Finance
2013-05-21 22:49:43.673 Pack[7543:c07] companyName: Risk Advisory
2013-05-21 22:49:43.673 Pack[7543:c07] companyName: Consulting

正如您再次看到的那样,第一个结果是 (null),我很难理解为什么会这样。

为了进一步调试,我运行了这个 NSLog:NSLog(@"companyName: %@", packName); 以将原始结果输出为数组,这些是结果:

2013-05-21 22:52:59.284 Pack[7581:c07] companyName: (
    "Audit",
    "Tax",
    "Digital",
    "Consulting",
    "Risk Advisory",
    "Finance",
    "Audit",
    "Tax",
    "Digital",
    "Consulting",
    "Advisory",
    "Finance"
)

数组中没有(null) 结果,所以我不知道这个流氓空值是从哪里来的。

任何帮助将不胜感激!!!!

【问题讨论】:

    标签: ios objective-c plist icarousel


    【解决方案1】:

    对于包含在 carousel:viewForItemAtIndex:reusingView: 中的第二个 NSLog,我输出 items 数组只是为了看看发生了什么。

    不,您输出的正是items 的一个元素:具有在 iCarousel 委托回调中传递的索引的那个。您无法控制 iCarousel 何时发送此消息并且未指定索引的顺序。这解释了以下输出

    2013-05-21 22:43:23.916 Pack[7496:c07] companyName: 0
    2013-05-21 22:43:23.918 Pack[7496:c07] companyName: 0
    2013-05-21 22:43:23.919 Pack[7496:c07] companyName: 11
    ...
    

    同样,前两个结果都是 0,并且与第一次迭代不同,排序非常混乱。我在 SO 上发现了一个线程,其中提到 plist 不一定按顺序输出,因为它们只是关键对象,所以我明白了,但核心问题是前两个结果。

    如上所述,顺序取决于 iCarousel 实现。它与 plist 无关。您误读了链接的帖子,它可能与字典中的顺序有关。当然,plist 会保留数组元素的顺序。

    如果我更改我的 NSLog 以输出 self.packName 的结果(如下所示:NSLog(@"companyName: %@", [self.packName objectAtIndex:index]);) 这是返回的内容:

    2013-05-21 22:49:43.663 Pack[7543:c07] companyName: (null)
    2013-05-21 22:49:43.665 Pack[7543:c07] companyName: Audit
    ...
    

    带有 (null) 结果的行只能表示一件事:在第一次回调时,items ivar 尚未初始化。 objectAtIndex: 永远无法返回 nil,所以这是唯一的解释。您可以使用调试器检查,在回调中设置断点和awakeFromNib

    【讨论】:

    • 感谢@Nikolai Ruhe 让我朝着正确的方向前进。如果您查看我上面的代码,您会发现在viewDidLoadawakeFromNib 中我两次拉入plist。解决方法是巩固这一点并将 plist 代码放在 awakeFromNib 中,然后将其从 viewDidLoad 中删除。
    猜你喜欢
    • 2021-03-25
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 2017-03-28
    • 2022-01-10
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多