zoukankan      html  css  js  c++  java
  • Swift-----类型转换 、 嵌套类型 、 扩展 、 协议 、 访问控制

    1 使用is和as操作符判断和转换数组中的对象类型
    
    1.1 问题
    
    类型转换可以判断实例的类型,也可以将实例看做是其父类或者子类的实例。在Swift中使用is和as操作符实现类型转换。
    
    本案例定义一个媒体类MediaItem,它有两个子类Movie和Song,创建一个存放Movie实例和Song实例的媒体数组library,使用is和as操作符判断和转化library数组中的实例类型。
    
    1.2 方案
    
    使用类型检查操作符is来检查一个实例是否属于特定子类型,如果属于该子类型操作符返回true,否则返回false。
    
    某类型的一个常量或变量可能实际上属于某一个子类,使用类型转换操作符as可以将其转换成子类型。转换过程可能会失败,因此类型转换操作符有两种不同的形式,可选形式as?和强制形式as。
    
    1.3 步骤
    
    实现此案例需要按照如下步骤进行。
    
    步骤一:定义MediaItem类
    
    首先定义一个MediaItem媒体类,包含一个String类型的name属性,和一个init构造方法,代码如下所示:
    
     
    //媒体类
    class MediaItem {
    var name : String
    init(name:String){
    self.name = name
    }
    }
    然后定义MediaItem的两个子类,第一个子类Movie在父类的基础上增加一个director属性,和相应的构造方法。第二个子类Song,在父类的基础上增加了一个artist属性,和相应的构造方法,代码如下所示:
    
     
    //电影类
    class Movie : MediaItem {
    var director : String
    init(name: String, director:String){
    self.director = director
    super.init(name: name)
    }
    }
    //歌曲类
    class Song: MediaItem {
    var airtist : String
    init(name: String, airtist: String) {
    self.airtist = airtist
    super.init(name: name)
    }
    }
    最后一个创建一个数组常量library,包含两个Movie实例和三个Song实例,library的类型是在它被初始化时根据它数组中包含的内容推断来的,Swift的类型检测能够推断出Movie和Song有共同的父类MediaItem,所以推断出library的类型是MediaItem[],从library中取出的也是MediaItem类型,代码如下所示:
    
     
    //媒体数组
    let library /*: [MediaItem]*/ = [
    Movie(name: "星际穿越", director: "Daniel"),
    Song(name: "小苹果", airtist: "筷子兄弟"),
    Movie(name: "Breaking Bad", director: "Guodh"),
    Song(name: "最炫民族风", airtist: "凤凰传奇"),
    Song(name: "菊花台", airtist: "Jay")
    ]
    步骤二:检测类型
    
    定义两个变量movieCount和songCount,用来计算数组library中Movie和Song类型的实例数量。
    
    遍历数组library中的每一个实例,使用is操作符判断类型,代码如下所示:
    
     
    //电影多少部?歌曲多少首
    var movieCount = 0
    var songCount = 0
    //is用于判断引用指向的对象是否是指定类型
    for item in library {
    if item is Movie {
    movieCount++
    }else if item is Song {
    songCount++
    }
    }
    movieCount
    songCount
    运行结果如图-1所示:
    
    
    图-1
    
    步骤三:转换类型
    
    遍历library里的每一个MediaItem实例,并打印出适当的描述,item需要真正作为Movie或Song的类型来使用,这是需要使用as操作符进行类型转换,代码如下所示:
    
     
    //遍历每个媒体,并打印详细信息
    for item in library {
    if item is Movie {
    //as用于强制装换,能转就转,不能转的话程序直接崩溃
    let movie = item as! Movie
    println("电影名:(movie.name),导演:(movie.director)")
    }else if item is Song {
    let song = item as! Song
    println("歌曲名:(song.name), 演唱者:(song.airtist)")
    }
    }
    但是数组中的每一个item可能是Movie或Song,所以这里使用可选类型的转换符更合适,代码如下所示:
    
     
    for item in library {
    //as?与as功能相同,能转就转,不能转返回nil,程序不会崩溃,返回的是一个可选值
    if let movie = item as? Movie {
    println("电影名:(movie.name),导演:(movie.director)")
    } else if let song = item as? Song {
    println("歌曲名:(song.name), 演唱者:(song.airtist)")
    }
    }
    1.4 完整代码
    
    本案例中,完整代码如下所示:
    
     
    import UIKit
    //媒体类
    class MediaItem {
    var name : String
    init(name:String){
    self.name = name
    }
    }
    //电影类
    class Movie : MediaItem {
    var director : String
    init(name: String, director:String){
    self.director = director
    super.init(name: name)
    }
    }
    //歌曲类
    class Song: MediaItem {
    var airtist : String
    init(name: String, airtist: String) {
    self.airtist = airtist
    super.init(name: name)
    }
    }
    //媒体数组
    let library /*: [MediaItem]*/ = [
    Movie(name: "星际穿越", director: "Daniel"),
    Song(name: "小苹果", airtist: "筷子兄弟"),
    Movie(name: "Breaking Bad", director: "Guodh"),
    Song(name: "最炫民族风", airtist: "凤凰传奇"),
    Song(name: "菊花台", airtist: "Jay")
    ]
    //电影多少部?歌曲多少首
    var movieCount = 0
    var songCount = 0
    //is用于判断引用指向的对象是否是指定类型
    for item in library {
    if item is Movie {
    movieCount++
    }else if item is Song {
    songCount++
    }
    }
    movieCount
    songCount
    //遍历每个媒体,并打印详细信息
    for item in library {
    if item is Movie {
    //as用于强制装换,能转就转,不能转的话程序直接崩溃
    let movie = item as! Movie
    println("电影名:(movie.name),导演:(movie.director)")
    }else if item is Song {
    let song = item as! Song
    println("歌曲名:(song.name), 演唱者:(song.airtist)")
    }
    }
    for item in library {
    //as?与as功能相同,能转就转,不能转返回nil,程序不会崩溃,返回的是一个可选值
    if let movie = item as? Movie {
    println("电影名:(movie.name),导演:(movie.director)")
    } else if let song = item as? Song {
    println("歌曲名:(song.name), 演唱者:(song.airtist)")
    }
    }
     
    
    2 扩展的使用
    
    2.1 问题
    
    扩展就是向一个已有的类、结构体或枚举添加新功能,和OC的分类类似。本案例演示Swift中扩展的用法,包括在扩展中添加计算属性、构造方法。实例方法和类型方法等。
    
    2.2 方案
    
    Swift中的扩展可以向已有的类型添加计算型实例属性和计算型类型属性,但是不可以添加存储属性,也不可以向已有属性添加属性观测器。
    
    扩展还可以向已有的类型添加新的构造器,新构造器有责任保证构造过程能够让所有属性全都初始化。对于类而言扩展只能添加新的便利构造器,不能添加新的指定构造器和析构方法,指定构造器和析构方法必须总是由原始的类提供。
    
    扩展可以向已有类型添加新的实例方法和类型方法。
    
    2.3 步骤
    
    实现此案例需要按照如下步骤进行。
    
    步骤一:添加计算型属性
    
    下面这个例子向已有的类型添加计算型属性,向Swift中的Double类型添加五个计算型实例属性,从而提供对距离单位的支持,这些属性都是可以通过点语法来访问。
    
    这些属性表达的含义是把一个Double类型的值看做是某单位下的长度值,1.0用来表示一米单位为m,其他单位则需要一些转换来表示在米下测量的值,km表示千米,ft表示英尺,cm表示厘米,mm表示毫米。
    
    这些属性都是只读的计算属性,所以可以省略get关键字,返回类型都是Double类型,代码如下所示:
    
    extension Double {
    var km:Double {
    return self*1000
    }
    var m:Double {
    return self
    }
    var cm:Double {
    return self/100
    }
    var mm:Double {
    return self/1000
    }
    var ft:Double {
    return self/3.28084
    }
    }
    let oneIch = 25.4.mm
    let threeFeet = 3.ft
    运行结果如图-2所示:
    
    
    图-2
    
    步骤二:添加构造方法
    
    定义一个用于描述几何矩形的定制结构体Rect,这个例子同时定义了两个辅助结构体Size和Point,0.0作为所有属性的默认值,代码如下所示:
    
     
    struct Point {
    var x = 0.0
    var y = 0.0
    }
    struct Size {
    var width = 0.0
    var height = 0.0
    }
    struct Rect {
    var origin = Point()
    var size = Size()
    }
    再使用扩展提供一个额外的构造器,可以使用中心点来进行构造,代码如下所示:
    
     
    extension Rect {
    init(center:Point,size:Size) {
    var originX = center.x - size.width/2
    var originY = center.y - size.height/2
    self.origin = Point(x: originX, y: originY)
    self.size = size
    }
    }
    var rect = Rect(center: Point(x: 20, y: 10), size: Size( 10, height: 10))
    运行结果如图-3所示:
    
    
    图-3
    
    步骤三:添加方法
    
    向Int类型添加一个名为repetitions的新的实例方法,代码如下所示:
    
     
    extension Int {
    func repetition(task:()->()) {
    for i in 0...self {
    task()
    }
    }
    }
    var i = 3
    i.repetition({println("hehe")})
    运行结果如图-4所示:
    
    
    图-4
    
    2.4 完整代码
    
    本案例中,完整代码如下所示:
    
     
    import UIKit
    //扩展计算属性
    extension Double {
    var km:Double {
    return self*1000
    }
    var m:Double {
    return self
    }
    var cm:Double {
    return self/100
    }
    var mm:Double {
    return self/1000
    }
    var ft:Double {
    return self/3.28084
    }
    }
    let oneIch = 25.4.mm
    let threeFeet = 3.ft
    //扩展构造器
    struct Point {
    var x = 0.0
    var y = 0.0
    }
    struct Size {
    var width = 0.0
    var height = 0.0
    }
    struct Rect {
    var origin = Point()
    var size = Size()
    }
    extension Rect {
    init(center:Point,size:Size) {
    var originX = center.x - size.width/2
    var originY = center.y - size.height/2
    self.origin = Point(x: originX, y: originY)
    self.size = size
    }
    }
    var rect = Rect(center: Point(x: 20, y: 10), size: Size( 10, height: 10))
    //扩展方法
    extension Int {
    func repetition(task:()->()) {
    for i in 0...self {
    task()
    }
    }
    }
    var i = 3
    repetition({println("hehe")})
     
    
    3 计时器
    
    3.1 问题
    
    本案例学习使用Swift语言使用纯代码的方式实现第一个Swift项目——一个简单的计时器,如图-5,图-6所示:
    
    
    图-5-6
    
    3.2 方案
    
    首先使用Xcode创建一个SingleViewApplication项目,编程语言选择Swift,可以看到Xcode已经提供的项目代码全都换成Swift语言实现,如图-7所示:
    
    
    图-7
    
    本案例采用纯代码的方式实现所以删除Storyboard,将程序的MainInterface清空,在程序的启动方法中,采用手写代码的方式创建的window,如图-8所示:
    
    
    图-8
    
    接下来使用代码搭建计时器项目的界面,界面上方是一个现实倒计时的Label控件,下方是一排预设的时间按钮,最下方是启动和复位按钮。
    
    扩展可以向已有类型添加新的实例方法和类型方法。
    
    3.3 步骤
    
    实现此案例需要按照如下步骤进行。
    
    步骤一:创建window对象和根视图控制器
    
    首先在AppDeleagte类中程序加载完成的方法中创建一个和屏幕大小一样的window对象,并将window的背景颜色设置为白色,代码如下所示:
    
     
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    //可选链,设置背景颜色
    self.window?.backgroundColor = UIColor.whiteColor()
    self.window?.makeKeyAndVisible()
    return true
    }
    然后创建window的根视图控制器,根视图控制器是ViewController类型,Swift项目中不需要导入头文件就可以使用项目中定义好的ViewController类,代码如下所示:
    
     
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    //可选链,设置背景颜色
    self.window?.backgroundColor = UIColor.whiteColor()
    //创建根视图控制器
    self.window?.rootViewController = ViewController()
    self.window?.makeKeyAndVisible()
    return true
    }
    由上面的代码可以看出OC语言提供的类和方法完全可以在Swift中使用,只是换成Swift的语法而已,IOS程序的运行原理和开发思想与之前所学完全一致。
    
    步骤二:搭建界面
    
    计时器的界面上方是一个现实倒计时的Label控件,下方是一排预设的时间按钮,最下方是启动和复位按钮,首先将这些控件全都设置为ViewController的存储属性,在viewDidLoad方法中进行初始状态的设置,布局代码写在viewDidLayoutSubviews方法中,代码如下所示:
    
     
    class ViewController: UIViewController {
    var timeLabel:UILabel!
    var timeButtons:[UIButton]!
    var startButton:UIButton!
    var resetButton:UIButton!
    func setupTimeLabel(){
    timeLabel = UILabel()
    timeLabel.textColor = UIColor.whiteColor()
    timeLabel.font = UIFont.boldSystemFontOfSize(80)
    timeLabel.backgroundColor = UIColor.blackColor()
    timeLabel.textAlignment = NSTextAlignment.Center
    view.addSubview(timeLabel)
    }
    //预设时间按钮的信息
    let timeButtonsInfo = [("1min",60),("3min",180),("5min",300),("sec",1)]
    func setupTimeButtons(){
    timeButtons = []
    for (title,sec) in timeButtonsInfo {
    let button = UIButton()
    button.backgroundColor = UIColor.orangeColor()
    button.setTitle(title, forState:UIControlState.Normal)
    button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
    button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Highlighted)
    //记录对应的时间给tag
    button.tag = sec
    view.addSubview(button)
    timeButtons.append(button)
    }
    }
    func timeButtonTapped (button:UIButton){
    remainingSeconds = button.tag
    }
    //设置启动,复位按钮
    func setupActionButtons() {
    startButton = UIButton()
    startButton.backgroundColor = UIColor.redColor()
    startButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
    startButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
    startButton.setTitle("Start", forState: .Normal)
    view.addSubview(startButton)
    resetButton = UIButton()
    resetButton.backgroundColor = UIColor.redColor()
    resetButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
    resetButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
    resetButton.setTitle("Reset", forState: .Normal)
    view.addSubview(resetButton)
    }
    override func viewDidLoad() {
    super.viewDidLoad()
    setupTimeLabel()
    setupTimeButtons()
    setupActionButtons()
    }
    //布局代码
    override func viewDidLayoutSubviews() {
    //时间窗口的布局
    timeLabel.frame = CGRect(x: 10, y: 40,  view.bounds.size.width-20, height: 120)
    //时间按钮的布局:按钮大小:64x44,按钮之间的间隔
    let cnt = timeButtons.count - 1
    let width = view.bounds.width - 10*2.0 - CGFloat(timeButtons.count) * 64.0
    let gap = width / CGFloat(cnt)
    for (index, button) in enumerate(timeButtons) {
    let buttonLeft = 10.0 + CGFloat(index) * (64.0 + gap)
    button.frame = CGRectMake(CGFloat(buttonLeft), view.bounds.height-120.0, 64, 44)
    }
    //启动复位按钮的布局
    startButton.frame = CGRectMake(10, view.bounds.height - 60, view.bounds.width - 20 - 100, 44)
    resetButton.frame = CGRectMake(10 + startButton.frame.width+20, view.bounds.height - 60, 80, 44)
    }
    }
    运行程序完成的界面如图-9所示:
    
    
    图-9
    
    步骤三:实现计时功能
    
    首先设置一个记录当前剩余秒数的属性remainingSeconds,该属性是一个整型的计算属性,当remainingSeconds的值发生改变就更新timeLabel的显示内容,因此给该属性添加一个属性监视器,通过newValue计算出timeLabel显示的内容,代码如下所示:
    
     
    //计算剩余时间
    var remainingSeconds:Int = 0 {
    //属性监视器
    willSet {
    let min = newValue/60
    let sec = newValue%60
    timeLabel.text = String(NSString(format: "%02d:%02d", min,sec))
    }
    }
    其次给预设时间按钮添加点击事件timeButtonTapped:,该方法将用户选择的时间秒数赋值给remainingSeconds,代码如下所示:
    
     
    //预设时间按钮的信息
    let timeButtonsInfo = [("1min",60),("3min",180),("5min",300),("sec",1)]
    func setupTimeButtons(){
    timeButtons = []
    for (title,sec) in timeButtonsInfo {
    let button = UIButton()
    button.backgroundColor = UIColor.orangeColor()
    button.setTitle(title, forState:UIControlState.Normal)
    button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
    button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Highlighted)
    //记录对应的时间给tag
    button.tag = sec
    //给按钮添加点击事件
    button.addTarget(self, action: Selector("timeButtonTapped:"), forControlEvents: UIControlEvents.TouchUpInside)
    view.addSubview(button)
    timeButtons.append(button)
    }
    }
    func timeButtonTapped (button:UIButton){
    remainingSeconds += button.tag
    }
    然后给启动和复位按钮添加点击事件startButtonTapped:和resetButtonTapped:,代码如下所示:
    
     
    //设置启动,复位按钮
    func setupActionButtons() {
    startButton = UIButton()
    startButton.backgroundColor = UIColor.redColor()
    startButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
    startButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
    startButton.setTitle("Start", forState: .Normal)
    view.addSubview(startButton)
    //添加事件
    startButton.addTarget(self, action: "startButtonTapped:", forControlEvents: .TouchUpInside)
    resetButton = UIButton()
    resetButton.backgroundColor = UIColor.redColor()
    resetButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
    resetButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
    resetButton.setTitle("Reset", forState: .Normal)
    view.addSubview(resetButton)
    resetButton.addTarget(self, action: "resetButtonTapped:", forControlEvents: .TouchUpInside)
    }
    接下来需要实现startButtonTapped:和resetButtonTapped:方法,当点击启动按钮时计时器开始计时,因此需要开启一个timer。
    
    在实现startButtonTapped:和resetButtonTapped:方法之前需要在ViewController类中定义一个NSTimer类型的存储属性timer,以及一个用于记录当前计时状态的Bool类型的计算属性isCounting,并带有一个属性监视器。当isCounting属性值为true则表示当前处于计时状态,对timer进行初始化并开始计时,当isCounting属性值为false则表示当前停止计时,timer停止计时并清空,代码如下所示:
    
     
    //计时器计算属性
    var timer:NSTimer?
    var isCounting:Bool = false {
    //添加属性监视器,当计时开始创建timer否则停止
    willSet {
    if newValue {
    timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)
    }else {
    timer?.invalidate()
    timer = nil
    }
    setSettingButtonsEnabled(!newValue)
    }
    }
    //计时方法每一秒调用改变timeLable的显示,直到计时结束
    func updateTimer(timer:NSTimer){
    remainingSeconds--
    if remainingSeconds<=0 {
    isCounting = false
    var alertVC = UIAlertController(title: "时间到", message: "", preferredStyle:.Alert)
    let action = UIAlertAction(title: "确定", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
    println("被按了")
    })
    alertVC.addAction(action)
    self.presentViewController(alertVC, animated: true, completion: nil)
    }
    }
    //打开或关闭设置时间的按钮
    func setSettingButtonsEnabled(enable:Bool) {
    for button in timeButtons {
    button.enabled = enable
    button.alpha = enable ?1.0 : 0.3
    }
    resetButton.enabled = enable
    resetButton.alpha = enable ?1.0 : 0.3
    let title = enable ? "启动" : "停止"
    startButton.setTitle(title, forState: .Normal)
    }
    此时再实现startButtonTapped:和resetButtonTapped:方法,代码如下所示:
    
     
    func startButtonTapped(button:UIButton){
    isCounting = !isCounting
    }
    func resetButtonTapped(){
    remainingSeconds = 0
    }
    步骤四:后台计时,推送消息
    
    IOS8对程序的后台运行有很好的支持,当计时器退到后台,不用做任何操作就会自动后台计时,但是当计时完成用户并不知道计时已经完成,所以这个时候就需要使用IOS系统提供的本地消息推送功能,首先需要在程序加载成功的方法中请求用户同意接受消息推送,代码如下所示:
    
     
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    //可选链,设置背景颜色
    self.window?.backgroundColor = UIColor.whiteColor()
    self.window?.rootViewController = ViewController()
    self.window?.makeKeyAndVisible()
    //请求用户获取消息推送权限
    let settings = UIUserNotificationSettings(forTypes: UIUserNotificationType.Alert | UIUserNotificationType.Sound | UIUserNotificationType.Badge,categories: nil)
    application.registerUserNotificationSettings(settings)
    return true
    }
    其次从计时开始就添加消息推送,当计时完成时推送消息,代码如下所示:
    
     
    func startButtonTapped(button:UIButton){
    isCounting = !isCounting
    if isCounting {
    //添加消息推送
    createAndFireLocalNotificationAfterSeconds(Double(remainingSeconds))
    }else {
    //计时结束退出消息推送
    UIApplication.sharedApplication().cancelAllLocalNotifications()
    }
    }
    //添加消息推送方法
    func createAndFireLocalNotificationAfterSeconds(seconds:NSTimeInterval) {
    UIApplication.sharedApplication().cancelAllLocalNotifications()
    let notification = UILocalNotification()
    //推送时间
    notification.fireDate = NSDate(timeIntervalSinceNow: seconds)
    //推送时区
    notification.timeZone = NSTimeZone.systemTimeZone()
    //推送通知的内容
    notification.alertBody = "Time is up!"
    UIApplication.sharedApplication().scheduleLocalNotification(notification)
    }
    运行程序消息推送效果如图-10所示:
    
    
    图-10
    
    3.4 完整代码
    
    本案例中,AppDelegate.swift文件中完整代码如下所示:
    
     
    import UIKit
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    //可选链,设置背景颜色
    self.window?.backgroundColor = UIColor.whiteColor()
    self.window?.rootViewController = ViewController()
    self.window?.makeKeyAndVisible()
    //请求用户获取消息推送权限
    let settings = UIUserNotificationSettings(forTypes: UIUserNotificationType.Alert | UIUserNotificationType.Sound | UIUserNotificationType.Badge,categories: nil)
    application.registerUserNotificationSettings(settings)
    return true
    }
    }
     
    本案例中,ViewController.swift文件中完整代码如下所示:
    
     
    import UIKit
    class ViewController: UIViewController {
    var timeLabel:UILabel!
    var timeButtons:[UIButton]!
    var startButton:UIButton!
    var resetButton:UIButton!
    //计算剩余时间
    var remainingSeconds:Int = 0 {
    //属性监视器
    willSet {
    let min = newValue/60
    let sec = newValue%60
    timeLabel.text = String(NSString(format: "%02d:%02d", min,sec))
    }
    }
    //计时器计算属性
    var timer:NSTimer?
    var isCounting:Bool = false {
    //添加属性监视器,当计时开始创建timer否则停止
    willSet {
    if newValue {
    timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)
    }else {
    timer?.invalidate()
    timer = nil
    }
    setSettingButtonsEnabled(!newValue)
    }
    }
    //计时方法每一秒调用改变timeLable的显示,直到计时结束
    func updateTimer(timer:NSTimer){
    remainingSeconds--
    if remainingSeconds<=0 {
    isCounting = false
    var alertVC = UIAlertController(title: "time is up", message: "", preferredStyle:.Alert)
    let action = UIAlertAction(title: "Done", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
    println("被按了")
    })
    alertVC.addAction(action)
    self.presentViewController(alertVC, animated: true, completion: nil)
    }
    }
    //打开或关闭设置时间的按钮
    func setSettingButtonsEnabled(enable:Bool) {
    for button in timeButtons {
    button.enabled = enable
    button.alpha = enable ?1.0 : 0.3
    }
    resetButton.enabled = enable
    resetButton.alpha = enable ?1.0 : 0.3
    let title = enable ? "Start" : "Stop"
    startButton.setTitle(title, forState: .Normal)
    }
    func setupTimeLabel(){
    timeLabel = UILabel()
    timeLabel.textColor = UIColor.whiteColor()
    timeLabel.font = UIFont.boldSystemFontOfSize(80)
    timeLabel.backgroundColor = UIColor.blackColor()
    timeLabel.textAlignment = NSTextAlignment.Center
    view.addSubview(timeLabel)
    }
    //预设时间按钮的信息
    let timeButtonsInfo = [("1min",60),("3min",180),("5min",300),("sec",1)]
    func setupTimeButtons(){
    timeButtons = []
    for (title,sec) in timeButtonsInfo {
    let button = UIButton()
    button.backgroundColor = UIColor.orangeColor()
    button.setTitle(title, forState:UIControlState.Normal)
    button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
    button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Highlighted)
    //记录对应的时间给tag
    button.tag = sec
    //给按钮添加点击事件
    button.addTarget(self, action: Selector("timeButtonTapped:"), forControlEvents: UIControlEvents.TouchUpInside)
    view.addSubview(button)
    timeButtons.append(button)
    }
    }
    func timeButtonTapped (button:UIButton){
    remainingSeconds += button.tag
    }
    //设置启动,复位按钮
    func setupActionButtons() {
    startButton = UIButton()
    startButton.backgroundColor = UIColor.redColor()
    startButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
    startButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
    startButton.setTitle("Start", forState: .Normal)
    view.addSubview(startButton)
    //添加事件
    startButton.addTarget(self, action: "startButtonTapped:", forControlEvents: .TouchUpInside)
    resetButton = UIButton()
    resetButton.backgroundColor = UIColor.redColor()
    resetButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
    resetButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
    resetButton.setTitle("Reset", forState: .Normal)
    view.addSubview(resetButton)
    resetButton.addTarget(self, action: "resetButtonTapped:", forControlEvents: .TouchUpInside)
    }
    func startButtonTapped(button:UIButton){
    isCounting = !isCounting
    if isCounting {
    //添加消息推送
    createAndFireLocalNotificationAfterSeconds(Double(remainingSeconds))
    }else {
    //计时结束退出消息推送
    UIApplication.sharedApplication().cancelAllLocalNotifications()
    }
    }
    func resetButtonTapped(button:UIButton){
    remainingSeconds = 0
    }
    //添加消息推送方法
    func createAndFireLocalNotificationAfterSeconds(seconds:NSTimeInterval) {
    //取消之前所有的消息推送
    UIApplication.sharedApplication().cancelAllLocalNotifications()
    let notification = UILocalNotification()
    //推送时间
    notification.fireDate = NSDate(timeIntervalSinceNow: seconds)
    //推送时区
    notification.timeZone = NSTimeZone.systemTimeZone()
    //推送通知的内容
    notification.alertBody = "Time is up!"
    UIApplication.sharedApplication().scheduleLocalNotification(notification)
    }
    override func viewDidLoad() {
    super.viewDidLoad()
    setupTimeLabel()
    setupTimeButtons()
    setupActionButtons()
    }
    //布局代码
    override func viewDidLayoutSubviews() {
    //时间窗口的布局
    timeLabel.frame = CGRect(x: 10, y: 40,  view.bounds.size.width-20, height: 120)
    //时间按钮的布局:按钮大小:64x44,按钮之间的间隔
    let cnt = timeButtons.count - 1
    let width = view.bounds.width - 10*2.0 - CGFloat(timeButtons.count) * 64.0
    let gap = width / CGFloat(cnt)
    for (index, button) in enumerate(timeButtons) {
    let buttonLeft = 10.0 + CGFloat(index) * (64.0 + gap)
    button.frame = CGRectMake(CGFloat(buttonLeft), view.bounds.height-120.0, 64, 44)
    }
    //启动复位按钮的布局
    startButton.frame = CGRectMake(10, view.bounds.height - 60, view.bounds.width - 20 - 100, 44)
    resetButton.frame = CGRectMake(10 + startButton.frame.width+20, view.bounds.height - 60, 80, 44)
    }
    }
     
  • 相关阅读:
    常见模块和包
    二分查找算法
    常见内置函数
    Django总目录
    nginx配置站点
    Arduino语言
    Python连接Arduino的方法
    机器人学习
    Redis
    arduino总目录
  • 原文地址:https://www.cnblogs.com/52190112cn/p/5052173.html
Copyright © 2011-2022 走看看