iOS Today Extension 在 iPhone 上不断崩溃,而不是在模拟器中

iOS Today Extension keeps crashing on iPhone, not in simulator

我正在尝试构建一个 iOS Today Extension,它显示三张图片和一些文本。在模拟器里它运行没问题,但是当我在我的iPhone上运行它时,它闪烁三下然后显示Unable to Load。我做错了什么?

TodayViewController.m

#import "TodayViewController.h"
#import <NotificationCenter/NotificationCenter.h>
#import "UIImageView+WebCache.h"
#import "SDImageCache.h"

@interface TodayViewController () <NCWidgetProviding>

@property (strong, nonatomic) UILabel *descriptionLabel;

@property (strong, nonatomic) UIImageView *firstImage;
@property (strong, nonatomic) UIImageView *secondImage;
@property (strong, nonatomic) UIImageView *thirdImage;

@property (strong, nonatomic) UILabel *firstImageLabel;
@property (strong, nonatomic) UILabel *secondImageLabel;
@property (strong, nonatomic) UILabel *thirdImageLabel;

@property (strong, nonatomic) UILabel *firstImageOwnerLabel;
@property (strong, nonatomic) UILabel *secondImageOwnerLabel;
@property (strong, nonatomic) UILabel *thirdImageOwnerLabel;

@property (strong, nonatomic) NSDictionary *dataOne;
@property (strong, nonatomic) NSDictionary *dataTwo;
@property (strong, nonatomic) NSDictionary *dataThree;

@property (nonatomic) NSInteger quarterSize;
@property (nonatomic) NSInteger eightSize;

@end

@implementation TodayViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    self.preferredContentSize = CGSizeMake(self.view.frame.size.width, 320);

    [self updateNumberLabelText];

    if ([self.dataOne count] == 0) {
        UILabel *noContent = [[UILabel alloc] initWithFrame:CGRectMake((self.view.frame.size.width/2)-150, 93, 300, 44)];
        noContent.text = @"You haven't opened the app yet.";
        [self.view addSubview:noContent];
    } else {
        NSString *deviceType = [UIDevice currentDevice].model;

        if([deviceType isEqualToString:@"iPhone"] || [deviceType isEqualToString:@"iPhone Simulator"])
        {
            self.quarterSize = self.view.frame.size.width/4;
            self.eightSize = self.quarterSize/4;
        } else if([deviceType isEqualToString:@"iPad"] || [deviceType isEqualToString:@"iPad Simulator"])
        {
            self.quarterSize = self.view.frame.size.width/5;
            self.eightSize = self.quarterSize/4;
        }

        self.descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.eightSize, 15, self.view.frame.size.width-self.quarterSize, 20)];
        self.descriptionLabel.text = @"Some new images just for you!";
        self.descriptionLabel.textColor = [UIColor whiteColor];
        [self.view addSubview:self.descriptionLabel];

        UIView *firstView = [[UIView alloc] initWithFrame:CGRectMake(self.eightSize, 45, self.quarterSize, self.quarterSize*2)];
        UITapGestureRecognizer *singleFingerTap =
        [[UITapGestureRecognizer alloc] initWithTarget:self
                                            action:@selector(openFirstImage:)];
    [firstView addGestureRecognizer:singleFingerTap];

        if ([[self.dataOne objectForKey:@"imageurl"] isEqualToString:@"empty"]) {
            UIView *noImageOne = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.quarterSize, self.quarterSize*1.25)];
            noImageOne.backgroundColor = [self paperColorLightBlue500];
            [firstView addSubview:noImageOne];
        } else {
            self.firstImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.quarterSize, self.quarterSize*1.25)];
            __block UIActivityIndicatorView *activityIndicator;
            __weak UIImageView *weakImageView = self.firstImage;
            [self.firstImage sd_setImageWithURL: [NSURL URLWithString:[self.dataOne objectForKey:@"imageurl"]]
                 placeholderImage:[UIImage imageNamed:@"placeholder.png"]
                              options:SDWebImageProgressiveDownload
                             progress:^(NSInteger receivedSize, NSInteger expectedSize) {
                                 if (!activityIndicator) {
                                     [weakImageView addSubview:activityIndicator = [UIActivityIndicatorView.alloc initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]];
                                     activityIndicator.center = weakImageView.center;
                                     [activityIndicator startAnimating];
                                 }
                             }
                            completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                                [activityIndicator removeFromSuperview];
                                activityIndicator = nil;
                            }];
            self.firstImage.contentMode = UIViewContentModeScaleAspectFill;
            [self.firstImage setClipsToBounds:YES];

            [firstView addSubview:self.firstImage];
        }

        UIView *secondView = [[UIView alloc] initWithFrame:CGRectMake(firstView.frame.origin.x + firstView.frame.size.width + self.eightSize, 45, self.quarterSize, self.quarterSize*2)];
        UITapGestureRecognizer *secondFingerTap =
        [[UITapGestureRecognizer alloc] initWithTarget:self
                                            action:@selector(openSecondImage:)];
        [secondView addGestureRecognizer:secondFingerTap];

        if ([[self.dataTwo objectForKey:@"imageurl"] isEqualToString:@"empty"]) {
            UIView *noImageTwo = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.quarterSize, self.quarterSize*1.25)];
            noImageTwo.backgroundColor = [self paperColorLightBlue500];
            [secondView addSubview:noImageTwo];
        } else {
            self.secondImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.quarterSize, self.quarterSize*1.25)];
            __block UIActivityIndicatorView *activityIndicator;
            __weak UIImageView *weakImageView = self.secondImage;
            [self.secondImage sd_setImageWithURL: [NSURL URLWithString:[self.dataTwo objectForKey:@"imageurl"]]
                                 placeholderImage:[UIImage imageNamed:@"placeholder.png"]
                                          options:SDWebImageProgressiveDownload
                                         progress:^(NSInteger receivedSize, NSInteger expectedSize) {
                                             if (!activityIndicator) {
                                                 [weakImageView addSubview:activityIndicator = [UIActivityIndicatorView.alloc initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]];
                                                 activityIndicator.center = weakImageView.center;    
                                                 [activityIndicator startAnimating];
                                             }
                                         }
                                        completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                                            [activityIndicator removeFromSuperview];
                                            activityIndicator = nil;
                                        }];
            self.secondImage.contentMode = UIViewContentModeScaleAspectFill;
            [self.secondImage setClipsToBounds:YES];

            [secondView addSubview:self.secondImage];
        }

        UIView *thirdView = [[UIView alloc] initWithFrame:CGRectMake(secondView.frame.origin.x + secondView.frame.size.width + self.eightSize, 45, self.quarterSize, self.quarterSize*2)];
        UITapGestureRecognizer *thirdFingerTap =
        [[UITapGestureRecognizer alloc] initWithTarget:self
                                            action:@selector(openThirdImage:)];
        [thirdView addGestureRecognizer:thirdFingerTap];

        if ([[self.dataThree objectForKey:@"imageurl"] isEqualToString:@"empty"]) {
            UIView *noImageThird = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.quarterSize, self.quarterSize*1.25)];
            noImageThird.backgroundColor = [self paperColorLightBlue500];
            [thirdView addSubview:noImageThird];
        } else {
            self.thirdImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.quarterSize, self.quarterSize*1.25)];
            __block UIActivityIndicatorView *activityIndicator;
            __weak UIImageView *weakImageView = self.thirdImage;
            [self.thirdImage sd_setImageWithURL: [NSURL URLWithString:[self.dataThree objectForKey:@"imageurl"]]
                                  placeholderImage:[UIImage imageNamed:@"placeholder.png"]
                                       options:SDWebImageProgressiveDownload
                                          progress:^(NSInteger receivedSize, NSInteger expectedSize) {
                                              if (!activityIndicator) {
                                                  [weakImageView addSubview:activityIndicator = [UIActivityIndicatorView.alloc initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]];
                                                  activityIndicator.center = weakImageView.center;
                                                  [activityIndicator startAnimating];
                                              }
                                          }
                                         completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                                             [activityIndicator removeFromSuperview];
                                             activityIndicator = nil;
                                         }];
            self.thirdImage.contentMode = UIViewContentModeScaleAspectFill;
            [self.thirdImage setClipsToBounds:YES];

            [thirdView addSubview:self.thirdImage];
        }

        self.firstImageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.firstImage.frame.origin.y + self.firstImage.frame.size.height + 10, self.quarterSize, 20)];
        self.firstImageLabel.text = [self.dataOne objectForKey:@"title"];
        self.firstImageLabel.numberOfLines = 2;
        self.firstImageLabel.textColor = [UIColor whiteColor];
        self.firstImageLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:13];
        [self.firstImageLabel sizeToFit];
        [firstView addSubview:self.firstImageLabel];

        self.secondImageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.firstImage.frame.origin.y + self.firstImage.frame.size.height + 10, self.quarterSize, 20)];
        self.secondImageLabel.text = [self.dataTwo objectForKey:@"title"];
        self.secondImageLabel.numberOfLines = 2;
        self.secondImageLabel.textColor = [UIColor whiteColor];
        self.secondImageLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:13];
        [self.secondImageLabel sizeToFit];
        [secondView addSubview:self.secondImageLabel];

        self.thirdImageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.firstImagele.frame.origin.y + self.firstImage.frame.size.height + 10, self.quarterSize, 20)];
        self.thirdImageLabel.text = [self.dataThree objectForKey:@"title"];
        self.thirdImageLabel.numberOfLines = 2;
        self.thirdImageLabel.textColor = [UIColor whiteColor];
        self.thirdImageLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:13];
        [self.thirdImageLabel sizeToFit];
        [thirdView addSubview:self.thirdImageLabel];

        self.firstImageOwnerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.firstImageLabel.frame.origin.y + self.firstImageLabel.frame.size.height, self.quarterSize, 30)];
        self.firstImageOwnerLabel.text = [self.dataOne objectForKey:@"owner"];
        self.firstImageOwnerLabel.numberOfLines = 1;
        self.firstImageOwnerLabel.textColor = [UIColor lightGrayColor];
        self.firstImageOwnerLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:11];
        [firstView addSubview:self.firstImageOwnerLabel];
        [self.view addSubview:firstView];

        self.secondImageOwnerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.firstImageLabel.frame.origin.y + self.firstImageLabel.frame.size.height, self.quarterSize, 30)];
        self.secondImageOwnerLabel.text = [self.dataTwo objectForKey:@"owner"];
        self.secondImageOwnerLabel.numberOfLines = 1;
        self.secondImageOwnerLabel.textColor = [UIColor lightGrayColor];
        self.secondImageOwnerLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:11];
        [secondView addSubview:self.secondImageOwnerLabel];
        [self.view addSubview:secondView];

        self.thirdImageOwnerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.firstImageLabel.frame.origin.y + self.firstImageLabel.frame.size.height, self.quarterSize, 30)];
        self.thirdImageOwnerLabel.text = [self.dataThree objectForKey:@"owner"];
        self.thirdImageOwnerLabel.numberOfLines = 1;
        self.thirdImageOwnerLabel.textColor = [UIColor lightGrayColor];
        self.thirdImageOwnerLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:11];
        [thirdView addSubview:self.thirdImageOwnerLabel];
        [self.view addSubview:thirdView];
    }
}

- (UIColor *)paperColorLightBlue500     { return UIColorFromRGB(0x03a9f4); }

- (void)openFirstImage:(UITapGestureRecognizer *)recognizer {
    NSLog(@"Please open the First Image");
}

- (void)openSecondImage:(UITapGestureRecognizer *)recognizer {
    NSLog(@"Please open the Second Image");
}

- (void)openThirdImage:(UITapGestureRecognizer *)recognizer {
    NSLog(@"Please open the Third Image");
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(userDefaultsDidChange:)
                                                 name:NSUserDefaultsDidChangeNotification
                                               object:nil];
    }
    return self;
}

- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets
{
    return UIEdgeInsetsZero;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    self.firstImageLabel = nil;
    self.secondImageLabel = nil;
    self.thirdImageLabel = nil;
    self.firstImageOwnerLabel = nil;
    self.secondImageOwnerLabel = nil;
    self.thirdImageOwnerLabel = nil;
}

- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler {
    // Perform any setup necessary in order to update the view.

    // If an error is encountered, use NCUpdateResultFailed
    // If there's no update required, use NCUpdateResultNoData
    // If there's an update, use NCUpdateResultNewData

    completionHandler(NCUpdateResultNewData);
}

- (void)userDefaultsDidChange:(NSNotification *)notification {
    [self updateNumberLabelText];
}

- (void)updateNumberLabelText {
    NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.testapp.TodayExtensionDefaults"];
    self.dataOne = [defaults objectForKey:@"dataOne"];
    self.dataTwo = [defaults objectForKey:@"dataTwo"];
    self.dataThree = [defaults objectForKey:@"dataThree"];

    for (id key in self.dataOne) {
        NSLog(@"key: %@, value: %@ \n", key, [self.dataOne objectForKey:key]);
    }

    for (id key in self.dataThree) {
        NSLog(@"key: %@, value: %@ \n", key, [self.dataThree objectForKey:key]);
    }
}

@end

我得到的唯一错误是扩展名是 Terminated due to Memory Error

扩展程序的内存限制比普通应用程序低得多。你必须调查为什么你的扩展使用了这么多内存。也许有泄漏。