0

我正在制作一个新闻阅读应用程序。我有一个用作分页控制器的ArticleDetailPagingVC 。这有一个带有多个ArticleDetailViewController的 UIScrollView 。

ArticleDetailViewController内部是一个处理 articleText 的 UIWebView。

更改一些代码后,我在尝试在 UIWebView 中注入 HTML 字符串时得到了 EXC_BAD_ACCESS。我最终找到了 NSZombie's,我发现:

MOFO NSZOMBIE

如屏幕截图所示,NSZombie 指向设置ArticleDetailViewController的框架,我认为这是不正确的。

如果我注释掉将 HTMLString 注入我的 UIWebView 的代码行,则视图将按原样显示,而 UIWebView 中没有任何数据。

WebView 被创建为 IBOutlet:

@property (nonatomic) IBOutlet UIWebView *webView;

委托设置为自我(ArticleDetailViewController

此外,它在调用任何 UIWebView 委托方法之前崩溃。

我确定问题不在于:

  • HTML 字符串(它之前工作过,如果我加载一个“Hello world”字符串,它也会崩溃)
  • 多线程(出于测试目的,一切都在主线程上处理)
  • 我没有弱属性
  • 我的代码中有 0 个 autoreleasepool's / CFRelease(object)

我不知道过早发布了什么会导致崩溃所以我的问题是,你如何调试这样的 NSZombie?或者任何其他指针都非常感谢。

寻呼VC.h

#import <UIKit/UIKit.h>
#import "DDScrollViewController.h"
#import "ThumbArticle.h"
#import "NewsArticle.h"
#import "MBProgressHUD.h"

#import "DDScrollViewDelegate.h"

@interface ArticleDetailPagingVC : UIViewController <UIScrollViewDelegate,MBProgressHUDDelegate>

//View
@property (nonatomic) IBOutlet UIScrollView *scrollView;

//Data
@property (nonatomic) ThumbArticle *selectedThumbArticle;
@property (nonatomic) NewsArticle *selectedNewsArticle;
@property (nonatomic) int indexOfSelectedArticle;
@property (nonatomic) NSMutableArray *dataList;
@property (nonatomic) NSInteger selectedPage;

@property (nonatomic) BOOL dataSet;

@property (nonatomic) MBProgressHUD *mbProcess;


-(id)initWithDataList:(NSMutableArray*)dataList;

@end

寻呼VC.m

#import "ArticleDetailPagingVC.h"
#import "ArticleDetailViewController.h"

@interface ArticleDetailPagingVC ()
-(void)setupView;
-(void)setupViewWithThumbArticles;
-(void)setupViewWithNewsArticles;
@end

@implementation ArticleDetailPagingVC

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        self.dataSet = NO;
    }
    return self;
}

-(id)initWithDataList:(NSMutableArray*)dataList
{
    self = [super init];
    if (self) {
        self.dataSet = NO;
        self.dataList = [NSMutableArray arrayWithArray:dataList];
    }
    return self;
}

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

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    if (self.selectedThumbArticle) {
        self.indexOfSelectedArticle = [self.dataList indexOfObject:self.selectedThumbArticle];
    } else if (self.selectedNewsArticle) {
        self.indexOfSelectedArticle = [self.dataList indexOfObject:self.selectedNewsArticle];
    }
}

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self setupView];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark -
#pragma mark Custom Methods

-(void)setupView
{
    if (self.dataList.count > 0) {

        id object = [self.dataList objectAtIndex:0];
        if ([object isKindOfClass:[NewsArticle class]]) {



        } else if ([object isKindOfClass:[ThumbArticle class]]) {
            ArticleDetailViewController *articleDetailVC = [[ArticleDetailViewController alloc] init];
            articleDetailVC.selectedThumbArticle = [self.dataList objectAtIndex:self.indexOfSelectedArticle];
            articleDetailVC.view.frame = CGRectMake(self.indexOfSelectedArticle * self.scrollView.frame.size.width, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
            [self.scrollView addSubview:articleDetailVC.view];
            //[articleDetailVC layoutViewWithThumbArticle:[self.dataList objectAtIndex:self.indexOfSelectedArticle]];
        }

        self.scrollView.contentSize = CGSizeMake(self.dataList.count * self.scrollView.frame.size.width, self.scrollView.frame.size.height);
        [self.scrollView setContentOffset:CGPointMake(self.indexOfSelectedArticle * self.scrollView.frame.size.width, 0) animated:NO];

        self.dataSet = YES;
    }
}

-(void)setupViewWithThumbArticles
{
    //Set the selected article first
    /*
    ArticleDetailViewController *articleDetailVC = [[ArticleDetailViewController alloc] init];
    dispatch_async(dispatch_get_main_queue(), ^{
        articleDetailVC.view.frame = CGRectMake(indexOfSelectedArticle * self.scrollView.frame.size.width, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
        [self.scrollView addSubview:articleDetailVC.view];
    });
    [self.viewControllers replaceObjectAtIndex:indexOfSelectedArticle withObject:articleDetailVC];
    [articleDetailVC layoutViewWithThumbArticle:[self.dataList objectAtIndex:indexOfSelectedArticle]];
    //Then loop through the rest to add them to the scrollview
     */
    int i = 0;
    for (ThumbArticle *article in self.dataList) {
        if (i != self.indexOfSelectedArticle) {
            ArticleDetailViewController *articleDetailVC = [[ArticleDetailViewController alloc] init];
            dispatch_async(dispatch_get_main_queue(), ^{
                articleDetailVC.view.frame = CGRectMake(i * self.scrollView.frame.size.width, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
                [self.scrollView addSubview:articleDetailVC.view];
            });
            //[self.viewControllers replaceObjectAtIndex:i withObject:articleDetailVC];
        }
        i++;
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        self.scrollView.contentSize = CGSizeMake(i * self.scrollView.frame.size.width, self.scrollView.frame.size.height);
        [self.scrollView setContentOffset:CGPointMake(self.indexOfSelectedArticle * self.scrollView.frame.size.width, 0) animated:NO];
    });
}

-(void)setupViewWithNewsArticles
{
    int indexOfSelectedArticle = [self.dataList indexOfObject:self.selectedNewsArticle];
    ArticleDetailViewController *articleDetailVC = [[ArticleDetailViewController alloc] init];
    dispatch_async(dispatch_get_main_queue(), ^{
        articleDetailVC.view.frame = CGRectMake(indexOfSelectedArticle * self.scrollView.frame.size.width, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
        [self.scrollView addSubview:articleDetailVC.view];
    });
    //[self.viewControllers replaceObjectAtIndex:indexOfSelectedArticle withObject:articleDetailVC];
    [articleDetailVC layoutViewWithNewsArticle:[self.dataList objectAtIndex:indexOfSelectedArticle]];

    int i = 0;
    for (NewsArticle *article in self.dataList) {
        if (i != indexOfSelectedArticle) {
            ArticleDetailViewController *articleDetailVC = [[ArticleDetailViewController alloc] init];
            dispatch_async(dispatch_get_main_queue(), ^{
                articleDetailVC.view.frame = CGRectMake(i * self.scrollView.frame.size.width, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
                [self.scrollView addSubview:articleDetailVC.view];
            });
            //[self.viewControllers replaceObjectAtIndex:i withObject:articleDetailVC];
        }
        i++;
    }
    self.scrollView.contentSize = CGSizeMake(i * self.scrollView.frame.size.width, self.scrollView.frame.size.height);
    [self.scrollView setContentOffset:CGPointMake(indexOfSelectedArticle * self.scrollView.frame.size.width, 0) animated:NO];
}

#pragma mark -
#pragma mark UIScrollView Delegate Methods

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (fmodf(scrollView.contentOffset.x, scrollView.frame.size.width) == 0) {
        if (self.dataSet) {
            self.selectedPage = scrollView.contentOffset.x / self.scrollView.frame.size.width;
            ArticleDetailViewController *articleDetailVC = [[ArticleDetailViewController alloc] initWithNibName:@"ArticleDetailViewController" bundle:nil];
            articleDetailVC.view.frame = CGRectMake(self.selectedPage * self.scrollView.frame.size.width, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
            [self.scrollView addSubview:articleDetailVC.view];
            [articleDetailVC layoutViewWithThumbArticle:[self.dataList objectAtIndex:self.selectedPage]];
        }
    }
}

#pragma mark -
#pragma mark MBProgressHUDDelegate methods

- (void)hudWasHidden
{
    [self.mbProcess removeFromSuperview];
}

@end

文章DetailViewController.h

#import "DDViewController.h"
#import "ThumbArticle.h"
#import "NewsArticle.h"
#import "MBProgressHUD.h"
#import "DDAsyncParser+NewsArticles.h"

@interface ArticleDetailViewController : DDViewController <MBProgressHUDDelegate,UIWebViewDelegate,ParserDelegate>

//View
@property (nonatomic,strong) IBOutlet UIView *contentView;
@property (nonatomic) IBOutlet UIImageView *image;
@property (nonatomic) IBOutlet UILabel *labelCategory;
@property (nonatomic) IBOutlet UILabel *labelImgCaption;
@property (nonatomic) IBOutlet UILabel *labelEdition;
@property (nonatomic) IBOutlet UIWebView *webView;
@property (nonatomic) IBOutlet UIActivityIndicatorView *activity;

@property (nonatomic) NSUInteger textFontSize;

@property (nonatomic) MBProgressHUD *mbProcess;

//Data
@property (nonatomic) ThumbArticle *selectedThumbArticle;

文章DetailViewController.m

#import "ArticleDetailViewController.h"
#import "DDUtilities.h"
#import "DDUserDefaults.h"
#import "NewsArticle.h"
#import "DDFeedParser.h"

@interface ArticleDetailViewController ()
@property (nonatomic) NewsArticle *parsedNewsArticle;
-(void)loadData;
-(void)updateImageCaptionLabel;
-(void)populateWebView;
@end

@implementation ArticleDetailViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        [self.view addSubview:self.contentView];
        ((UIScrollView*)self.view).contentSize = self.contentView.frame.size;
        self.dataSet = NO;
    }
    return self;
}

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

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    if (!self.dataSet) {
        [[DDAsyncParser sharedInstance] parseArticleWithXMLURL:self.selectedThumbArticle.articleXMLUrl delegate:self];
    }
}

- (void)viewWillUnload
{
    [self.webView setDelegate:nil];
    [self.webView stopLoading];
}

- (void)viewWillDisappear:(BOOL)animated{
    [self.webView setDelegate:nil];
    [self.webView stopLoading];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark -
#pragma mark Public Methods

-(void)layoutViewWithThumbArticle:(ThumbArticle*)article
{
    if (!self.dataSet) {
        self.selectedThumbArticle = article;
        [[DDAsyncParser sharedInstance] parseArticleWithXMLURL:self.selectedThumbArticle.articleXMLUrl delegate:self];
    }
}

-(void)layoutViewWithNewsArticle:(NewsArticle*)article
{
    if (!self.dataSet) {
        self.parsedNewsArticle = article;
        [self loadData];
    }
}

#pragma mark -
#pragma mark Private Methods

-(void)loadData
{
    self.labelCategory.text = self.parsedNewsArticle.articleCategory;
    self.labelCategory.font = kCalibriBold14;
    self.labelCategory.textColor = kGrayColor;

    self.labelEdition.text = self.parsedNewsArticle.articleEdition;
    self.labelEdition.font = kCalibriBold14;
    self.labelEdition.textColor = kGrayColor;

    [self updateImageCaptionLabel];
    [self populateWebView];

    self.dataSet = YES;
}

-(void)updateImageCaptionLabel
{
    self.labelImgCaption.text = @"";
    NSString *imgAuthor = @"";
    if (self.parsedNewsArticle.articleImgAuthor.length != 0) {
        imgAuthor = [NSString stringWithFormat:@"Foto: %@",self.parsedNewsArticle.articleImgAuthor];
    }
    NSString *imgCaption = @"";
    if (self.parsedNewsArticle.articleImgDescription.length != 0) {
        imgCaption = [NSString stringWithFormat:@"%@ \n%@",self.parsedNewsArticle.articleImgDescription,imgAuthor];
    } else {
        imgCaption = imgAuthor;
    }

    self.labelImgCaption.text = imgCaption;
    CGSize maximumLabelSize = CGSizeMake(296,9999);
    CGSize expectedLabelSize = [imgCaption sizeWithFont:self.labelImgCaption.font
                                      constrainedToSize:maximumLabelSize
                                          lineBreakMode:self.labelImgCaption.lineBreakMode];

    CGRect newFrame = self.labelImgCaption.frame;
    newFrame.size.height = expectedLabelSize.height;
    self.labelImgCaption.frame = newFrame;
}

-(void)populateWebView
{
    NSString *htmlContentString = [DDUtilities createHTMLStringForArticleDetail:self.parsedNewsArticle];
    [self.webView loadHTMLString:htmlContentString baseURL:nil];
}

-(void)checkSavedTextFontSize
{
    self.textFontSize = [[DDUserDefaults getValueForKey:@"textFontSize"]integerValue];
    if (self.textFontSize != 0) {
        NSString *jsString = [[NSString alloc] initWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'",
                              self.textFontSize];
        [self.webView stringByEvaluatingJavaScriptFromString:jsString];
    } else {
        self.textFontSize = 100;
    }
}

#pragma mark -
#pragma mark UIWebView Delegate

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    if (navigationType == UIWebViewNavigationTypeLinkClicked)
    {
        [[UIApplication sharedApplication] openURL:[request URL]];
        return NO;
    }

    return YES;
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    [self checkSavedTextFontSize];
    CGRect frame = webView.frame;
    frame.size.height = 1;
    webView.frame = frame;
    CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
    frame.size = fittingSize;
    dispatch_async(dispatch_get_main_queue(), ^{
        self.webView.frame = CGRectMake(frame.origin.x, self.labelImgCaption.frame.origin.y + self.labelImgCaption.frame.size.height + 5.0f, frame.size.width, frame.size.height);
        self.contentView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.webView.frame.origin.y + self.webView.frame.size.height + 30.0f);
        ((UIScrollView*)self.view).contentSize = self.contentView.frame.size;
    });

    //[DDUtilities setImageView:self.image forLink:self.parsedNewsArticle.articleImgUrl placeholder:YES withActivityIndicator:self.activity];
}

-(void)webViewDidStartLoad:(UIWebView *)webView
{

}

-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{

}

#pragma mark -
#pragma mark MBProgressHUDDelegate methods

- (void)hudWasHidden
{
    [self.mbProcess removeFromSuperview];
}

#pragma mark -
#pragma mark ParserDelegate methods

-(void)didFinishWithObject:(id)object
{
    self.parsedNewsArticle = object;
    [self loadData];
}
4

1 回答 1

3

您创建一个控制器(它有一个视图)。您将视图分配为某个其他视图的子视图。就是这样。因此,ARC 将有助于销毁您不再使用的文章详细信息控制器。当它尝试调用委托时,它已将自己设置为委托的任何内容(如 Web 视图)现在都会崩溃。

解决方案:存储文章详细信息控制器(添加强属性),以便在显示视图时保留它。

或者,将控制器添加为智利视图控制器。

于 2013-08-08T15:00:48.210 回答