我正在制作一个新闻阅读应用程序。我有一个用作分页控制器的ArticleDetailPagingVC 。这有一个带有多个ArticleDetailViewController的 UIScrollView 。
ArticleDetailViewController内部是一个处理 articleText 的 UIWebView。
更改一些代码后,我在尝试在 UIWebView 中注入 HTML 字符串时得到了 EXC_BAD_ACCESS。我最终找到了 NSZombie's,我发现:
如屏幕截图所示,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];
}