前言
在正式写第一行swift代码之前,我已经观望swift很久了,眼看着WWDC宣布swift诞生,看着swift1.0版本一路到2.0,等啊等,等待swift的成熟。
后来我不想等了,虽然目前用swift的团队还不是很多,但是它是苹果新技术的未来,这是无可争议的事实,不如早点接触,还能能早点享受到知识的喜悦。其实经过一年半的时间,swift已经逐渐稳定下来,现在已经是合适的时机了。
不同于oc语言,swift采用标准的开源开发流程,面向全世界的coder,在开源的知识浪潮中,你是否也能跳进去扎个猛子呢?
用新的技术去实现点什么,总是让人充满成就感。那就来一发UITableView
吧。
很有意思的是,swift为了降低iOSer的学习成本,尽量沿用了ios原有的类名、方法名、枚举等内容,使你一眼看去就觉得很亲切,上手难度降低很多。
首先新建一个工程,这个不需要详说,我的这个工程的目标是:用tableview做一个列表,每一行展示一个appstore在线应用的名称,并对应一个下载按钮,最终实现一个应用下载列表。
新建工程,准备在ViewController上开刀接下来将会有一大波示例代码来袭。。。
1.首先定义几个数据信息
import UIKit
class ViewController: UIViewController {
let btnStartTag:Int = 1000 //定义btn的tag起始值
//数组,其中的数据是(String,String)格式的元组
//其内容为列表的应用名和对应的appstore链接
let name_links_tuples : [(String,String)] =
[
]
//初始化table,为了简化代码,frame为全屏尺寸
let table:UITableView = UITableView(frame:UIScreen.mainScreen().bounds, style:UITableViewStyle.Plain)
}
这里有个注意事项,table的初始化我写在了class区间内,不在method方法内,如果在oc这是绝对不允许的。写在class区间的数据在整个类中可以访问,而写在method内的数据只能在这个method内使用。(btnStartTag、name_links_tuples也是一样)
在swift中允许这样的特例,即允许在method之外调用方法来初始化数据,但其他方法调用仍需要写在method内。
为了说明这种特例,我们尝试调用table.delegate
编译器报错了,Expected declaration
,说明编译器不认同在method之外进行基本方法调用
2.接下来,把table添加到视图界面上
override func viewDidLoad() {
super.viewDidLoad()
//table添加到视图上,并声明delegate和datasource
self.view!.addSubview(table)
table.dataSource = self
table.delegate = self
}
3.实现dataSource和delegate协议
//在类声明后添加协议,类名与协议名并列
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource
添加协议后,编译器马上会报错,因为UITableViewDataSource
有两个必须实现的方法,numberOfRowsInSection
和cellForRowAtIndexPath
,如何不实现编译器就会报错,这是swift中更严格的安全检查。而其他的方法为Optional方法,是可选实现的。
//实现datasource协议
//table的行数
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return name_links_tuples.count
}
//cell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: nil)
let title :String = name_links_tuples[indexPath.row].0 //获取应用名
cell.textLabel!.text = title
//每一行有一个下载按钮
let btn:UIButton = UIButton(type: UIButtonType.Custom)
btn.frame = CGRectMake(UIScreen.mainScreen().bounds.width-100, 10, 80, 50)
btn.setTitle("下载", forState: UIControlState.Normal)
btn.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
btn.backgroundColor = UIColor.redColor()
btn.tag = indexPath.row+btnTag
btn.addTarget(self, action: "btnClick:", forControlEvents: UIControlEvents.TouchUpInside)
cell.contentView.addSubview(btn)
return cell
}
//table的cell高度,可选方法
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 70
}
//再实现个UITableViewDelegate
协议演示一下
//禁止cell被点击选中
func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
return nil
}
OK协议实现好了。iOSer会发现还是熟悉的味道,只是写法有些不同了而已。
4.实现btn的action方法
我们在每个cell上添加了action方法,接下来就要实现这个action
func btnClick(sender:UIButton) {
print("btn click \(sender.tag)")
let indexOfBtn :Int = sender.tag - btnTag
if indexOfBtn >= 0 && indexOfBtn < name_links_tuples.count //安全校验
{
let str = name_links_tuples[indexOfBtn].1
let url = NSURL(string: str)
if url != nil {
UIApplication.sharedApplication().openURL(url!)
}
}
}
5.最终效果
在上面的代码中,我们声明了tableview实例,实现了table的delegate和datasource协议,为cell自定义了按钮响应,整个demo已经完工。看一下效果:
最终效果,每个应用名对应一个下载按钮做完这个示例,有一些东西要总结一下:
-
变量的声明可以写在class范围内,但是对象方法调用必须写在method块内。
-
name_links_tuples是一个元组的数组,使用这种形式的原因是,
数组中数据顺序可预见,而字典中的数据顺序是根据key值hash之后排序的
。数组+元组的结合,是一个非常好的数据组合方式。
还有一个原因就是,当获取字典的某一个特定value时,写法很复杂
dic.values[ dic.startIndex.advancedBy(theIndex) ] //dictionary的写法
name_links_tuples[theIndex].1 //array+tuple写法
对比效果一目了然 -
NSIndexPath的row方法声明,依然是在UITableView类的文档中声明的,延续了oc的方式,坏处就是不方便查找。
-
我们看到的方法名依然是很熟悉的感觉,但是写法有很大不同,swift摒弃了[]中括号对的写法,减少了可能产生的括号对匹配错误,方法调用更简明。方法声明依然是模拟自然语言,例如
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
字面意思就是 我有一个tableview的方法,给我tableview indexpath参数,我给你返回cell。一个方法,就像写了一行叙述文字。 -
self.view!是强制解析可选类型,安全的写法应该是判断是否为空 if self.view != nil,但是这里我就简单处理了。cell.textLabel!.text也是类似的
-
在oc中的很多枚举,现在都变成了结构体,UIButtonType.Custom这样的写法使参数的意义更清晰,
当枚举全局唯一时可省略结构体名称
,例如
UIUserInterfaceIdiom.Pad
可缩略为.Pad
-
btn.titleLabel.text是错误写法,titleLabel无法正常初始化。应该用btn.setTitle()等方法调用,这样系统会对titleLabel进行初始化
-
Selector的写法依然是"btnClick:"这样的形式,
方法名+冒号:
组合,相信你写一次就懂了 -
命令行的输出,回归了c的print函数名,print("btn click(sender.tag)"),其中
\\(变量名)
是swift新的变量调用方法,更直接,可读性高。并且这里不需要声明变量类型,swift具有强大的自动判定类型的机制