引言:
2007年第一部iPhone问世后,智能手机开始了取代PC终端的脚步。
时间来到2016年。
在时代巨浪的推动下,如今,移动互联网已然成为了IT领域的主战场。今天的iOS应用程序已经再不是从前那简单、娇小的弱女子了。手机淘宝、网易海购等原生和Html5结合的超级App层出不穷。Hybrid模式大红大紫,却也先天不足。
在iOS开发领域,我一直钟爱IB。
IB的源代码由Xml所书写,生涩难读,难以驾驭。
所以,IB开发几乎都是在图形化界面中进行的。
但这却并未妨碍IB成为iOS开发中最具效率的开发方式。
至于个中原因,还是Xcode强大的GUI操作界面和IB灵活的 Runtime注入,AutoLayout简洁的适配设置,SizeClass的iPhone/iPad兼容设置。
有时我在想,如果将IB的源代码进化成Html5风格书写会有什么样的一番风景呢。
在我眼中,以IB书写界面为主流的iOS开发模式,是最有可能进化成为完美的Hybrid模式,试想一下,兼容H5的IB配合Xcode强大的IDE编辑器,会带来一种何等愉悦的开发体验,会产生一种何等优异的Hybrid模式。性能优异,界面动态,有序的将逻辑放在前端和后端。这才是我心目中的Hybrid—既可以轻松的随App一起打包,还拥有卓越的性能,又可以随时对界面进行动态替换。
从iOS App 支持通过Tag标记来延迟下载IB文件可以得出 ,这在技术实现上不会有任何问题。
可是一心要控制App的性能和质量的Apple会大开绿灯吗?
短期内应该不会,但动态界面,固定逻辑也许会成为可能。
好了,说了这么多,我们也应该开始今天的主题了。
第一章:常见崩溃排查
连awakeFromeNib都没有执行,程序却崩溃了
连viewDidLoad都没有执行,程序还是崩溃了
这个 控件/界面 才刚一使用,程序就已经崩溃了
只是改变一点看起来没有任何问题的layout,程序崩溃了
合并代码后我的IB文件突然打不开了
没有任何报错,没有任何警告,程序崩溃了,IB,IB,真真是让人又爱又恨
相信许多入行iOS开发不久,或者使用IB不久的朋友都有遇到过这样的问题。这也是很多朋友放弃在实际项目中使用IB的原因之一。
IB仿佛是一把双刃剑,极大的提升开发效率,有着优异视图解耦性,却也伴随着难缠的故障排查。
如果就到此而止了,您还会继续使用IB吗?
我想绝大部分开发者会放弃它,或者只使用Xib而放弃Storyboard,尤其是站在生产第一线的朋友们。
在实际开发中我也常常遇到这样的朋友,因为这样或者那样的原因而弃用了IB,或者仅仅用IB搭建了View,却用代码给它设置一切。
在我们实际开发中,如果不使用IB,或者不部分使用Storyboard,在开发效率上,明显会慢于有着AndroidStudio加成的Android player。
这让一向自称程序高富帅的我们情何以堪。
好了,言归正转。
常见崩溃点:
1、Terminating app due to uncaught exception ‘NSUnknownKeyException'
-IB控件关联代码错误
问题描述:
控件关联对象或者事件(拉线到代码)后,移除了代码中的(对象或者方法)却没有移除控件上的引用(Referencing)。此种情况必崩。
解决方案:
如果同一IB文件控件较少:
方案,展开IB右边工具栏,切换到 Connection Inspector(带箭头那个)。切换点击控件逐一排查 Referencing,先检查同一控件有无重复Referencing(通常情况下是更改了代码中的关联对象,而IB中没有移除原有的Referencing导致),如果有重复Referencing再检查哪一个是真正对应代码的Referencing。如果没有找到问题,再检查是否所有的关联在代码中都有对应的存在(包括事件 和方法)。
2、reason: [<UI*** 0x15550640> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key
-IB keyPath 设置错误(如果没用过keyPath参考 http://blog.youkuaiyun.com/bsn1928/article/details/51372197 )
问题描述:
控件设置了不存在的keyPath。或者不应该设置KeyPath的控件被设置了KeyPath。
此种情况必崩。
解决方案:
如果同一IB文件控件较少,使用方案1,反之使用方案2:
方案1,展开IB右边工具栏,切换到 Identity Inspector(方框带文档图标那个)。展开User Defiend Runtime Attributes,找到错误提示中这段代码 [<UI*** 0x15550640> setValue:forUndefinedKey:] 的键,按类名逐一检查Key Path是否为空,然后修复之。
方案2,右键 IB 文件 Open As -> Source Code。Command + F搜索 KeyPath=“” 。如果未找到,找到错误提示中这段代码 [<UI*** 0x15550640> setValue:forUndefinedKey:] 的键,按类名搜索之,逐一排查,是否设置了无法找到的KeyPath。找到后,移除此KeyPath即可修复(注:源代码中要按键值对删除,否则将无法编译通过,至于为什么,玩过Html的都应该知道)。(当然你也可以写个脚本来完成如此复杂的操作,这里只阐述原理)
第二章:利用IBDesignable创建自定义IB控件
1、准备:Xcode 7.* +
这里介绍一下Label控件的自定义,其它控件以此类推。
新建Swift工程IBExtension,新建 IBLabel 继承自 UILabel。在类开始前加入
@IBDesignable
代码如下
// 在OC中 IB_Designable
// 在OC中 IBInspectable
import UIKit
@IBDesignable
class IBLabel: UILabel {
@IBInspectable var cornerRadius:CGFloat = 0{
didSet{
layer.cornerRadius = cornerRadius
layer.masksToBounds = cornerRadius > 0
}
}
@IBInspectable var borderWidth:CGFloat = 0{
didSet{
layer.masksToBounds = cornerRadius > 0
layer.borderWidth = borderWidth
}
}
@IBInspectable var borderColor:UIColor?{
didSet{
layer.masksToBounds = borderColor != nil
layer.borderColor = borderColor?.CGColor
}
}
@IBInspectable var allowSelected:Bool = false{
didSet{
if allowSelected{
userInteractionEnabled = true
addGestureRecognizer(tap)
}
else{
isSelected = false
userInteractionEnabled = false
removeGestureRecognizer(tap)
}
}
}
@IBInspectable var hiddenBorderWhenSelected = false{
didSet{
if hiddenBorderWhenSelected {layer.borderWidth = 0}
else {layer.borderWidth = borderWidth}
}
}
@IBInspectable var isSelected:Bool = false{
didSet{
if !allowSelected{
backgroundColor = normalBackgroundColor
textColor = normalTextColor
return
}
if isSelected{
backgroundColor = selectedBackgroundColor
textColor = selectedTextColor
if hiddenBorderWhenSelected {layer.borderWidth = 0}
}
else{
backgroundColor = normalBackgroundColor
textColor = normalTextColor
if hiddenBorderWhenSelected {layer.borderWidth = borderWidth}
}
}
}
@IBInspectable var normalTextColor:UIColor?
@IBInspectable var selectedTextColor:UIColor?
@IBInspectable var normalBackgroundColor:UIColor?
@IBInspectable var selectedBackgroundColor:UIColor?
lazy var tap:UITapGestureRecognizer = {
let tapGesture = UITapGestureRecognizer()
tapGesture .addTarget(self, action: #selector(IBLabel.didSelected(_:)))
return tapGesture
}()
func didSelected(gesture:UITapGestureRecognizer) {
isSelected = !isSelected
}
}
打开IB新建Label 展开IB右边工具栏,切换到 Identity Inspector 在 Class 类中输入我们刚才创建的IBLabel
然后切换到 Attributes Inspector 这时你可以看到你的自定义属性
如果你成功了
你会感受到IB突然变得如此的强大
如果失败了
不要着急,点击 Editor->Automaticaly Referesh View
然后再切换回来
如果还不行
没关系,重启Xcode
第三章:使用Storyboard创建静态列表,并配置动态刷新方法(下期再讲解)