最近工作不是很忙,我花了两个星期的时间学习了一些swift。虽然swift出来快两年了,但是我一直没有去学习。近来听好多朋友说,他们已经开始用swift开发了,我决定学习一下swift基础的东西,在这里列出我一些学习总结。我不善于写文章,我就大片的粘上代码好了,有OC基础的人,基本上一看就懂了。
苹果总是能弄出一些与众不同的代码书写方式,比如oc中的字符串写法。果然swift也一样,我在写一些代码的时候总是弹出警告,点击修复,系统会帮我加上一个问好(?)或者叹号(!),我但是就有点蒙了,这是什么意思呢?我没有系统看过swift的东西,直接按照oc的基础自己琢磨着写,导致好多的坑。那么这两个符号到底什么意思呢?我开始在找资料,原来这里有大学问啊!我先告诉说答案吧,问号(?)表示可选值或显示拆包,叹号(!)表示隐式拆包。 一切的原因在于一个swift的一个新的类型:optional类型(可选值,可以有值,也可以没有值),这是oc没有的类型。在oc中声明一个变量,可以不用赋初始值,因为系统会给变量初值。在swift中,变量是没有默认值的,所以使用变量之前必须赋初始值。当在声明一个变量不想给初始值的时候,就可以声明一个optional类型,例如:
var delegate : XXXDelegate?在调用这个变量的时候,在后面也要加上“?”,如
self.delegate?.btnsAction(btn)这样的实质就是:当Optional没有值时,返回的nil其实就是Optional.None,即没有值。除了None以外,还有一个Some,当有值时就是被Some包装的真正的值,所以我们拆包的动作其实就是将Some里面的值取出来。当变量不可能为空的时候,就可以用隐式拆包,就是在变量后面跟”!“。比如声明的时候:
var delegate : XXXDelegate!这样在调用的时候变量后面就什么都不用加了。声明的显示可选值,也可以用!的方式调用。补充一点,在oc中,nill表示的是指针,只有对象才可以用nill,而在swift中,nill表示没有值,Int,Bool等在没有值得时候也是nill。 相关链接: http://blog.csdn.net/woaifen3344/article/details/30244201/ http://blog.csdn.net/zhangao0086/article/details/38640209
在oc中可以,可以重写get方法来实现懒加载。在swift中用关键字layz来实现懒加载。示例代码:
// 懒加载 lazy var myTableView : UITableView = { var myTableView = UITableView.init(frame:CGRectMake(0, 64, self.view.bounds.width, self.view.bounds.height - 64 - 49), style: UITableViewStyle.Plain) myTableView.backgroundColor = kBorderLineColor(); myTableView.tableFooterView = UIView.init() myTableView.delegate = self myTableView.dataSource = self //2.注册Cell myTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: ID) return myTableView }()//使用一个闭包来实例化该属性willSet在新的值被设置之前调用 willSet观察器会将新的属性值作为常量参数传入,在willSet的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称newValue表示。 didSet在新的值被设置之后立即调用 didSet观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名oldValue。 我们可以didSet方法里进行一些赋值后的操作,相当于oc中的重写set方法
var model : UserProfile = UserProfile(){ didSet{ nameL.text = model.name headerImageV.sd_setImageWithURL(NSURL.init(string: model.avatar_hd), placeholderImage: UIImage.init(named: "timeline_image_placeholder")) subL.text = model.userDescription } }网上的swift单例有很多种写法,我还是在套用oc中的写法,换汤不换药
//单例 class var sharedInstance: LCInterfaceManager { struct Static { static var onceToken: dispatch_once_t = 0 static var instance: LCInterfaceManager? = nil } dispatch_once(&Static.onceToken) { Static.instance = LCInterfaceManager() } return Static.instance! }相关链接: http://www.cocoachina.com/swift/20151207/14584.html
这部分直接上代码了
//协议代理 protocol xxxViewDelegate{ func btnsAction(btn:UIButton) -> Void } //声明代理 var delegate : LCProfileHeaderViewDelegate? //调用 @objc private func buttonAction(btn:UIButton) -> Void { self.delegate?.btnsAction(btn) } //遵守协议,实现代理方法 // MARK: - xxxViewDelegate extension xxxViewController:xxxDelegate{ func btnsAction(btn: UIButton) { if btn.tag == 101 { let VC = LCFridensListVC.init() self.navigationController!.pushViewController(VC, animated: true) } } }子这里我不去讲解swift闭包写法的原理,大家可以去网上学习,教程很多。我要举一个运用闭包实现方向传值的例子,相当于oc之中的block用法。 需求:AVc跳转到BVc中,在BVc中设置AVc的背景色为随机色。 AVc中的代码
import UIKit let ID = "Cell" class ViewController: UIViewController{ override func viewWillAppear(animated: Bool) { super.viewWillAppear(true) } override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { weak var weakSelf = self let VC = LCSTestVC.init() VC.initBack { (changeToColor) in weakSelf?.view.backgroundColor = changeToColor } self.presentViewController(VC, animated: true) {} } override func viewDidLoad(){ super.viewDidLoad() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }BBC中的代码
import UIKit class LCSTestVC: UIViewController { typealias changeLastVcBacgroundColor = (color:UIColor)->() var myFunc = changeLastVcBacgroundColor?() func initBack( mathFunction:(changeToColor:UIColor)->() ){ myFunc = mathFunction } override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.blueColor() } override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { let r:CGFloat = CGFloat(CGFloat(random())/CGFloat(RAND_MAX)) let g:CGFloat = CGFloat(CGFloat(random())/CGFloat(RAND_MAX)) let b:CGFloat = CGFloat(CGFloat(random())/CGFloat(RAND_MAX)) myFunc!(color: UIColor.init(red: r , green: g, blue: b, alpha: 1.0)) self.dismissViewControllerAnimated(true) { } } }选择多个可选值的写法
let calendarUnit : NSCalendarUnit = [.Year , .Month , .Day ,.Hour, .Minute , .Second]swift中没有宏的概念,那么怎么实现类似于oc中pch文件中的定义全局宏的方法呢?答案是可以利用全局函数。
import Foundation import UIKit let kScreenWidth = UIScreen.mainScreen().bounds.size.width let kScreenHeight = UIScreen.mainScreen().bounds.size.height func DLog(input:AnyObject, function:String = #function, line:Int = #line){ #if DEBUG print("- <func: \(function)> <line: \(line)>: \(input)") #else #endif } //大字 let kBigTextFont = UIFont.systemFontOfSize(16) //常规 let kMidTextFont = UIFont.systemFontOfSize(14) //小字 let kSmallTextFont = UIFont.systemFontOfSize(12) //边框粗细 let kBorderLineThickness : CGFloat = 0.8 //cell边线粗细 let kBorderCellLineThickness : CGFloat = 8 //RGB func RGBA (r:CGFloat, g:CGFloat, b:CGFloat, a:CGFloat) -> UIColor { return UIColor (red: r/255.0, green: g/255.0, blue: b/255.0, alpha: a) }现在的swift开发多数会用到混编。swift和oc是通过桥接文件来实现的。无论是在oc创建的项目中还中创建swift文件,还是在swift文件中创建oc文件,第一次都会自动提示建立桥接文件。名字为:xxx-Bridging-Header.h,并且自动添加文件路径。如果是导入另一只中语言的第三方库,就不会自动生成桥接文件,这时候就需要自己建立一个桥接文件。第一步:新建一个”.h”文件,也就是新建中的”Header.h“文件,名字可以模仿系统的写法”xxx(demo名字)-Bridging-Header.h“;第二步,桥接文件路径,在设置Build Settings 中搜索Bridging,结果中Objective-C Brindging Header 中拖入文件路径(前面的可以写成$(SRCROOT)/,这样就会自动生成项目文件路径,不会因为换了电脑就找不到文件路径),编译一下,就可以了。
在oc项目中引用swift文件,只需导入头文件
#import "项目名字-Swift.h"这个文件是隐藏的,在工程中看不见。导入这个文件后就可以在oc使用swift写的类了。
在swift文件中引用oc的类,在桥接文件中引入需要引用oc的类的头文件,编译一下,就可以使用oc的类了。
swift的中的函数可以有多个返回值,具体的运用还没有比较好的列子。这里只是据下一多返回值函数的写法: “` private func createItem(frame:CGRect , topText:String , bottomText:String) ->(button:UIButton ,topLabel: UILabel , bottomLabel:UILabel){ let btn = UIButton.init(frame: frame) let topL = UILabel.init() topL.font = UIFont.boldSystemFontOfSize(16) let bottomL = UILabel.init() bottomL.font = kMidTextFont bottomL.textColor = kMinBlackColor()
topL.text = topText topL.sizeToFit() topL.frame.size.width = frame.size.width topL.textAlignment = NSTextAlignment.Center bottomL.text = bottomText bottomL.sizeToFit() topL.frame.origin.x = btn.frame.size.width/2 - topL.frame.size.width/2 bottomL.frame.origin.x = btn.frame.size.width/2 - bottomL.frame.size.width/2 topL.frame.origin.y = btn.frame.size.height/2 - topL.frame.size.height/2 - 4 bottomL.frame.origin.y = btn.frame.size.height/2 + 4 btn.addSubview(topL) btn.addSubview(bottomL) return (btn , topL , bottomL) }//调用 let itemsLeft = self.createItem(CGRectMake(0, 0,frame.size.width/3, frame.size.height), topText: “0”, bottomText: “微博”) itemsLeft.button.tag = 100 itemsLeft.button.addTarget(self, action: #selector(LCProfileHeaderView.buttonAction(_:)), forControlEvents: UIControlEvents.TouchUpInside) self.statusCountLabel = itemsLeft.topLabel self.addSubview(itemsLeft.button)
“`
这部分跟swift没有什么关系,只是我以前一直在用代码的方式实现比如lable的大小的自适应。最近发现,其实xib中也可以做这些的。 需求:比如一个label后面跟着一个UIView,label的宽度随着字数的大小变换,这个功能是可以用xib实现的。 第一步,拖入控件,利用xib来控制好约束,这部分和平常xib的使用没有区别,不在讲述。 第二步,选中图中的label,操作如图:
第三步,保持选中label,操作 做完这些操作后,label的横向约束会变成虚线,大功告成。如果你的功能里有对最大宽度的控制,可以在layoutSubviews这个方法里用代码来控制。 目前我学习到的只有这些,以后有什么爬出的坑,再跟大家来分享吧。