Yee’s Blog

Practicing Thinking Learning Sharing .

iOS Q&A Session 1

Problem1

为什么对类 A 的 delegate 属性设置成weak 或者assgin 会deadlock 。但是换成strong 可以正常运行。 self 本身也是另外一个类的局部变量。

1
2
3
4
5
6
7
- (void)createFilterBarFor:(AJKBSearchEstateViewController *)vc
{
  AJKBrokerAPI *brokerAPI = [[AJKBrokerAPI alloc] init];
  brokerAPI.delegate = self;
  [brokerAPI sendGetFilterWordsRequest];
  self.viewController = vc;
}

这时候delegate 所指的对象已经被释放掉了。所以运行到这里会出现 EXC_BAD_ACCESEX。像这类EXC_BAD_ACCESEX问题主要缘于access released objects

1
2
3
if ([self.delegate respondsToSelector:@selector(didLoadFilterItemsSuccess:)]) {
  [self.delegate didLoadFilterItemsSuccess:filtersArrays];
}

一个正确的做法是将A类的实例,设置成B的property,然后保证 delegate 的属性 设置成weak or assign这样避免环形引用。如果一定要将其创建成一个B的局部变量,那么就得将A的delegate 属性创建成Strong,这样才不至于出现EXC_BAD_ACCESS。

Problem2

为什么程序运行到

1
imageView.image = strongSelf.arrowImageViews[oppsiteIndex];

会crash 呢? 而且会不断 调用 imageView setImage 方法。是不是因为 迭代器里 block 执行时异步的?但是UI绘制时在主线程??

1
2
3
4
5
6
7
8
9
10
__weak typeof(self) weakSelf = self;
[self.arrowImageViews enumerateObjectsUsingBlock:^(UIImageView *imageView, NSUInteger idx, BOOL *stop) {
  __strong typeof(weakSelf) strongSelf = weakSelf;
  if (idx == index) {
    imageView.image = strongSelf.arrowImageViews[imageIndex];
  } else {
    NSInteger oppsiteIndex = imageIndex ^ 1;
    imageView.image = strongSelf.arrowImageViews[oppsiteIndex];
  }
}];

原因:低级错误,arrowImageViews (UIImageView 类型) 写错了,应该时arrowImags UIImage 类型 如果是UI代码已运行就crash,通常是因为传值类型不匹配导致的。

Problem3

在执行完之后,为什么self.emptyBackgroundView 还在其superView 中呢??

1
2
3
if (self.emptyBackgroundView) {
  [self.emptyBackgroundView removeFromSuperview];
}

但是通过po [self.view subviews] 发现有许多重复的 emptyBackgroundView view 加在了subview 数组里面,导致移除该 emptyBackgroundView ,还有很多 emptyBackgroundView。 所以看上去,好像是没有被remove掉。 出现这种情况是因为,[ self addSubView self.emptyBackground] api callBack 调用,多次请求之后会出现重复addSubview。这样view 的hierarchy重复的subview 会增加。

1
2
3
4
<AJKBSearchNoResultView: 0x7a622da0; frame = (0 46; 320 478); layer = <CALayer: 0x7a65c300>>,
<AJKBSearchNoResultView: 0x7a626c50; frame = (0 46; 320 478); layer = <CALayer: 0x7a6f4660>>,
<AJKBSearchNoResultView: 0x7ac688f0; frame = (0 46; 320 478); layer = <CALayer: 0x7ac67f30>>,
<AJKBSearchNoResultView: 0x7ac69cf0; frame = (0 46; 320 478); layer = <CALayer: 0x7ac69d60>>,

通过手段改善:

1
2
3
if (![self.view.subviews containsObject:self.emptyBackgroundView]){
  [self.view addSubview:self.emptyBackgroundView];
}
Problem4

对于subview 比较复杂的页面,如果要保证某个view可见 可以使用

1
[self.view bringSubviewToFront:self.tableView];

解决self.tableView 被遮挡的问题。

Problem5

如果是给UITablView 中delegate赋值A类的instance,一定得注意其UITableViewDelegate的方法和 UIScrollViewDelegate 方法只能在同一个类的instance中实现。

Problem6
1
2
3
4
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if (self.navigationController.view.frame.origin.x > 0) {
  return;
}
Problem7

设置statusBar样式的方法

1
2
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
这是全局修改

设置navigationBar backgroundColor. iOS 7 和 iOS 6 有差异

1
2
3
4
5
6
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
  self.navigationController.navigationBar.barTintColor = NAVIGATIONBAR_COLOR;
  self.navigationController.navigationBar.translucent = YES;    
} else {
  self.navigationController.navigationBar.tintColor = NAVIGATIONBAR_COLOR;
}
Problem8

在TableView 试图回到最顶端,发现下面这个方法非常不稳定

1
[self.tableView setContentOffset:CGPointZero animated:YES];

换成下面这个方法

1
2
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
Problem9

UIViewController.view 其高度在 viewDidLoad 中ViewWillAppear 中是不同的。ViewWillAppear view 的高度已经去掉statusBar 和navigationBar 的高度。