[iOS]iOS开发常见问题

最近工作比较忙,学习到了很多平时不注意的知识,这篇文章是2015年记录的开发中遇到的一些问题,还有很多没来得及记录。

1、问题描述

在往viewController中添加UIScrollView时,滑动时,控件总是向下偏移一段距离,开始不知何故,一查,原来是当向controller中第一个添加的控件时UIScrollView时,系统automaticallyAdjustsScrollViewInsets默认是YES,会自动向下偏移64像素,就是status bar和导航栏的高度,但是这种依靠系统的方式一般不被采用,所以最好将其设置位NO。

也有说可以采用下面方法:self.edgesForExtendedLayout = UIExtendedEdgeNone;

2、问题描述

在设置status bar的颜色时,网上说在viewcontroller中覆写下面方法可以达到目的,但是在我的测试下,发现并没有执行下面的语句,我的viewcontroller是包含在UINavigationController中。

1
2
3
4
-(UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleDefault;
}

网上一博客给出的解释原因如下:

UINavigationController不会将 preferredStatusBarStyle方法调用转给它的子视图,而是由它自己管理状态,而且它也应该那样做.因为UINavigationController 包含了它自己的状态栏 因此就算 UINavigationController中的viewController 实现了 preferredStatusBarStyle方法 也不会调用 那 UINavigationController是怎么决定 该返回 UIStatusBarStyleLightContent 还是 UIStatusBarStyleDefault的呢? 它是基于它的 UINavigationBar.barStyle属性.默认(UIBarStyleDefault)的是黑色文本的状态栏 而 UIBarStyleBlack是设置为白色文本的状态栏 详见这篇文章

所以在有UINavigationController的情况下,优先起作用的是navigationbar.barStyle的属性,默认情况是黑色,如果想要显示白色字体,可以如下设置:

1
self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;

在没有UINavigationController或者隐藏uinavigationbar的情况下,是之前的方法起作用。

另外,在application:didFinishLaunchingWithOptions:中设置如下也不起作用[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];,还需要在info中添加View controller-based status bar appearance为NO,才行。这个设置在iOS9中也被deprecate了,里面推荐的做法是viewcontroller的preferredStatusBarStyle方法

但是测试时,上面的语句对启动页的status bar的颜色还无法控制,所以比较好的解决办法是启动页面隐藏status bar,启动后再显示出来,作两个动作可以达到目的。 在info中将Status bar is initially hidden设置为YES,然后在application:didFinishLaunchingWithOptions:中添加如下方法。

1
[[UIApplication sharedApplication] setStatusBarHidden:NO];

3、问题描述

下面的操作在viewcontroller中不起作用,当放在application:didLaunchOption中会起作用.

1
[[UINavigationBar appearance] setBarTintColor:[UIColor orangeColor]];

在viewcontroller中起作用的是这句,这个现象应该和appearance的工作机制有关.

1
self.navigationController.navigationBar.barTintColor = [UIColor blackColor];

4、遇到下面的警告提示,需要去配置中开启background task

You’ve implemented -[ application:performFetchWithCompletionHandler:], but you still need to add “fetch” to the list of your supported UIBackgroundModes in your Info.plist.

5、发现UINavigationBarDelegate这个协议,原来uinavigationbar也是一个堆栈的形式展现,于是也要把玩一下了,但是在使用现有SDK的navigationbar时,会报下面的错误,原来,必须是自定义的navigationbar才行。

‘Cannot call pushNavigationItem:animated: directly on a UINavigationBar managed by a controller.’

同时,查看sdk中的UINavigationController中的navigationbar,后面有一段注释The navigation bar managed by the controller. Pushing, popping or setting navigation items on a managed navigation bar is not supported.

所以,如果要使用这个协议,最好的办法就是先隐藏系统的navigationbar,然后使用自定义的navigationbar,这样就可以在不pushViewController得情况下,更新导航栏的内容,这是一种不错的方式。

6、问题描述

在viewcontroller中测试uisearchController内容时,发现每次退出该页面都会遇到下面的concole提示,百思不得其解,有网友说是系统的一个bug,也给出了一个解决办法。

1
 Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<UISearchController: 0x105c1bc80>)

解决办法:

1
2
3
- (void)dealloc {
    [self.searchController.view removeFromSuperview];
}

7、问题描述

1
2
3
4
5
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    [self setWithCoder:aDecoder];
    return self;
}

上面代码在Xcode7.1中编译出现下面警告:Convenience initializer missing a self call to another initializer在stackoverflow上找到解释,说是ios8以后,苹果在SDK中增加了NS_DESIGNATED_INITIALIZER的宏来定义初始化方法,CLang要求所有init开头的方法必须要调用self或super的initializer方法,不然会有warning,所以上面的方法最好加上[super initWithCoder]等有NS_DESIGNATED_INITIALIZER定义的方法。

但是还有一种情况比较棘手,就是定义NSObject的Category时覆写上面的方法,由于是NSObject类就导致其没有父类,此时可以这样:[self init]。

8、iOS的UIModalPresentationCurrentContext特性

模态半透明弹出框,在iOS8之前是采用上面的方式,但是到了ios8之后,就不行了,原因是SDK中作了修改,所以编码时也得跟进。

1
2
3
4
5
6
7
8
9
10
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {  
     controller.providesPresentationContextTransitionStyle = YES;  
     controller.definesPresentationContext = YES;  
     controller.modalPresentationStyle = UIModalPresentationOverCurrentContext;  
     [self presentViewController:controller animated:YES completion:nil];  
 } else {  
     self.view.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;  
     [self presentViewController:controller animated:NO completion:nil];  
     self.view.window.rootViewController.modalPresentationStyle = UIModalPresentationFullScreen;  
 }  

顺道也复习一下下面的信息

1
2
3
4
5
6
typedef enum {
    UIModalPresentationFullScreen = 0, //全屏展示
    UIModalPresentationPageSheet,  //弹出是弹出VC时,presented VC的高度和当前屏幕高度相同,宽度和竖屏模式下屏幕宽度相同,剩余未覆盖区域将会变暗并阻止用户点击,这种弹出模式下,竖屏时跟UIModalPresentationFullScreen的效果一样,横屏时候两边则会留下变暗的区域
    UIModalPresentationFormSheet,  //presented VC的高度和宽度均会小于屏幕尺寸,presented VC居中显示,四周留下变暗区域
    UIModalPresentationCurrentContext,  //半透明方式
} UIModalPresentationStyle;
作者: Peter
出处: http://codefunny.github.io/
本文基于
署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 Peter(包含链接)。