热门搜索 :
考研考公
您的当前位置:首页正文

swift编写tableview实战

来源:东饰资讯网

前言
在正式写第一行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有两个必须实现的方法,numberOfRowsInSectioncellForRowAtIndexPath,如何不实现编译器就会报错,这是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已经完工。看一下效果:

最终效果,每个应用名对应一个下载按钮

做完这个示例,有一些东西要总结一下:

  1. 变量的声明可以写在class范围内,但是对象方法调用必须写在method块内。

  2. name_links_tuples是一个元组的数组,使用这种形式的原因是,数组中数据顺序可预见,而字典中的数据顺序是根据key值hash之后排序的。数组+元组的结合,是一个非常好的数据组合方式。
    还有一个原因就是,当获取字典的某一个特定value时,写法很复杂
    dic.values[ dic.startIndex.advancedBy(theIndex) ] //dictionary的写法
    name_links_tuples[theIndex].1 //array+tuple写法
    对比效果一目了然

  3. NSIndexPath的row方法声明,依然是在UITableView类的文档中声明的,延续了oc的方式,坏处就是不方便查找。

  4. 我们看到的方法名依然是很熟悉的感觉,但是写法有很大不同,swift摒弃了[]中括号对的写法,减少了可能产生的括号对匹配错误,方法调用更简明。方法声明依然是模拟自然语言,例如
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    字面意思就是 我有一个tableview的方法,给我tableview indexpath参数,我给你返回cell。一个方法,就像写了一行叙述文字。

  5. self.view!是强制解析可选类型,安全的写法应该是判断是否为空 if self.view != nil,但是这里我就简单处理了。cell.textLabel!.text也是类似的

  6. 在oc中的很多枚举,现在都变成了结构体,UIButtonType.Custom这样的写法使参数的意义更清晰,当枚举全局唯一时可省略结构体名称,例如
    UIUserInterfaceIdiom.Pad 可缩略为 .Pad

  7. btn.titleLabel.text是错误写法,titleLabel无法正常初始化。应该用btn.setTitle()等方法调用,这样系统会对titleLabel进行初始化

  8. Selector的写法依然是"btnClick:"这样的形式,方法名+冒号:组合,相信你写一次就懂了

  9. 命令行的输出,回归了c的print函数名,print("btn click(sender.tag)"),其中\\(变量名)是swift新的变量调用方法,更直接,可读性高。并且这里不需要声明变量类型,swift具有强大的自动判定类型的机制


Top