前言:在学习Swift的过程中,在网上找到一个swift版的爱鲜蜂工程(http://www.jianshu.com/p/879f58fe3542#),十分感谢大神慷慨的分享。但是这个项目是Swift2.0版的,无法正常运行,花了一天的时间将这个项目改成3.0版可以正常使用的项目。其中各种坑。。。。但是还好最后终于可以正常使用了。
下面来介绍一下在2.0转到3.0的过程中,遇到的各种bug。
标注:下面会将改好的工程传到github上面,仅供学习,不做他用。
修改后的版本的github地址,请使用Xcode 8.0打开,9打开会一直提示你升级swift4,而且一些xib支持也会有点问题。
https://github.com/yaoyao66/-swift3.0.git
1.首先是最坑的一个,在解析JSON数据的时候,遍历模型字典返回数据为空?
- 最后发现判断一个可选择类型的对象是数组还是字典的方法出错了,在Swift2.0中使用
let type = "\(value.self?.classForCoder)" //获取当前对象的类型
但是这个方法在swift3.0中这个返回的值不是 NSDictionary或者 NSArray 字符串,所以我将这部分直接改成
if value is NSDictionary //判断这个可选类型对象的类型是否是NSDictionary
else if value is NSArray
2.Swift编译时报错:Command failed due to signal: Segmentation fault: 11
这个我首先用的是Xcode Beta9版的,你只要选择Xcode8版本的就可以了。
3.Xcode8版本的模拟器不见了?
应该是你打开了多个Xcode,将所有的Xcode和模拟器全部关掉,重新打开就可以了
4. 方法发生了变化
let p1 = transitionLayer.position;
let p3 = CGPoint(x: view.width - 40, y: self.view.layer.bounds.size.height - 40);
let positionAnimation = CAKeyframeAnimation(keyPath: "position")
let path = CGMutablePath();
// CGPathMoveToPoint(path, nil, p1.x, p1.y);
// CGPathAddCurveToPoint(path, nil, p1.x, p1.y - 30, p3.x, p1.y
- 30, p3.x, p3.y);
替换为
path.move(to: CGPoint(x:p1.x,y:p1.y));
path.addCurve(to: CGPoint(x:p3.x,y:p3.y), control1: CGPoint(x:p1.x,y:p1.y - 30), control2: CGPoint(x:p3.x,y:p1.y - 30));
positionAnimation.path = path;
5.override func animationDidStop(_ anim: CAAnimation, finished flag: Bool) 报下面的错误 Method does not override any method from its superclass
这是因为animationDidStop是CAAnimationDelegate里面的方法,所以在class加上CAAnimationDelegate代理,然后去掉override关键字就好了
6.sd_setImage(with:placeholderImage:completed:)’ 报下面的错误 Ambiguous use of 我查了一下资料,好像是有sd_setImage有2个方法太相近了,所以才会出现这个错误
代码修正为
backImageView.sd_setImage(with:URL(string: imageName!),placeholderImage: UIImage(named: placeholderImageName!),options:SDWebImageOptions()) { (image, error,_ ,_ ) in
7. Swift3.0中采用下面的方法来判断代理是否实现
if (delegate.customClassMapping != nil)
例子
swift2.0
if tmpSelf!.delegate != nil && ((tmpSelf!.delegate?.responds(to: #selector(HomeTableHeadViewDelegate.tableHeadView(_:iconClick:)))) != nil)
swift3.0 ?代替responds
if ((tmpSelf!.delegate?.tableHeadView(_:iconClick:)) != nil)
用weak定义代理
weak var delegate:DelegateName?
// - MARK: Delegate
//在Swift中,制定协议需要遵守NSObjectProtocol协议,除了类可以遵守协议,结构体也可以遵守协议
@objc protocol HomeTableHeadViewDelegate: NSObjectProtocol {
@objc optional func tableHeadView(_ headView: HomeTableHeadView, focusImageViewClick index: Int)
@objc optional func tableHeadView(_ headView: HomeTableHeadView, iconClick index: Int)
}
8. Swift3.0中通知
NotificationCenter.default.addObserver(self, selector: #selector(HomeViewController.homeTableHeadViewHeightDidChange(_:)), name: NSNotification.Name(rawValue: HomeTableHeadViewHeightDidChange), object: nil)
NotificationCenter.default.post(name: Notification.Name(rawValue: HomeTableHeadViewHeightDidChange), object: newValue)
9. Swift3.0中的逃逸闭包
如果闭包被作为参数传递到函数时,该闭包不需要立即执行而是需要等某些线程完成任务之后再执行,那么需要在该闭包前加上@escaping,否则编译器报错。如下代码所示:
convenience init(frame: CGRect, iconClick:@escaping ((_ index: Int) -> Void)) {
self.init(frame:frame)
self.iconClick = iconClick
}
10.Swift3.0循环
//正序 0...2 0 1 2 0 ..<2 0 1
for i in 0...2 {
let btn = UIButton()
}
//倒序
if subviews.count>1 {//在这里需要注意subviews.count的值一定要大于1,不然会出现错误
for i in (1...subviews.count).reversed() {
let subBtnView = self.subviews[i-1]
subBtnView.removeFromSuperview()
}
}
11.Swift3.0循环Block
HotView.swift
var iconClick:((_ index: Int) -> ())? //声明并定义一个block
convenience init(frame: CGRect, iconClick:@escaping ((_ index: Int) -> Void)) {
self.init(frame:frame)
self.iconClick = iconClick
}
//点击事件
func iconClick(_ tap: UITapGestureRecognizer) {
if iconClick != nil {
iconClick!(tap.view!.tag)
}
}
//页面上添加手势
let tap = UITapGestureRecognizer(target: self, action:#selector(HotView.iconClick(_:)))
icon.addGestureRecognizer(tap)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//点击页面,block回调
func buildHotView() {
weak var tmpSelf = self
hotView = HotView(frame: CGRect.zero, iconClick: { (index) -> Void in
if ((tmpSelf!.delegate?.tableHeadView(_:iconClick:)) != nil) {
tmpSelf!.delegate!.tableHeadView!(tmpSelf!, iconClick: index)
}
})
hotView?.backgroundColor = UIColor.white
addSubview(hotView!)
}
12.Swift3.0常用控件
//UIButton
let btn = UIButton()
btn.setTitle(buttonTitles[i], for: UIControlState())
btn.backgroundColor = UIColor.white
btn.layer.cornerRadius = 5
btn.tag = i
btn.titleLabel?.font = UIFont.systemFont(ofSize: 10)
btn.frame = CGRect(x: 30 + CGFloat(i) * ((ScreenWidth - btnW * 3 - 60) / 2 + btnW), y: blogLabel.frame.maxY + 10, width: btnW, height: 30)
btn.addTarget(self, action: #selector(AboltAuthorViewController.btnClick(_:)), for: UIControlEvents.touchUpInside)
btn.setTitleColor(UIColor.black, for: UIControlState())
view.addSubview(btn)
//UILabel
let buyCountLabel = UILabel()
buyCountLabel.isHidden = false
buyCountLabel.text = "0"
buyCountLabel.textColor = UIColor.black
buyCountLabel.textAlignment = NSTextAlignment.center
buyCountLabel.font = HomeCollectionTextFont
return buyCountLabel
13.didSet
属性观察者,类似于触发器。用来监视属性的除初始化之外的属性值变化,当属性值发生改变时可以对此作出响应。有如下特点:
- 1 不仅可以在属性值改变后触发didSet,也可以在属性值改变前触发willSet。
- 2 给属性添加观察者必须要声明清楚属性类型,否则编译器报错。
- 3 willSet可以带一个newName的参数,没有的话,该参数默认命名为newValue。
- 4 didSet可以带一个oldName的参数,表示旧的属性,不带的话默认命名为oldValue。
- 5 属性初始化时,willSet和didSet不会调用。只有在初始化上下文之外,当设置属性值时才会调用。
- 6 即使是设置的值和原来值相同,willSet和didSet也会被调用
//普通属性
var firstName:String = ""
var lastName:String = ""
var nickName:String = ""
//计算属性
var fullName:String
{
get
{
return nickName + " " + firstName + " " + lastName
}
}
//带属性监视器的普通属性
var age:Int = 0 {
//我们需要在age属性变化前做点什么
willSet
{
print("Will set an new value \(newValue) to age")
}
didSet {
print("age filed changed form \(oldValue) to \(age)")
if age<10
{
nickName = "Little"
}else
{
nickName = "Big"
}
}
}
//调用
let me = People()
me.firstName = "Li"
me.lastName = "Lei"
me.age = 30