• 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构造方法,代码如下所示:

     
    1. //媒体类
    2. class MediaItem {
    3. var name String
    4. init(name:String){
    5. self.name = name
    6. }
    7. }

    然后定义MediaItem的两个子类,第一个子类Movie在父类的基础上增加一个director属性,和相应的构造方法。第二个子类Song,在父类的基础上增加了一个artist属性,和相应的构造方法,代码如下所示:

     
    1. //电影类
    2. class Movie : MediaItem {
    3. var director String
    4. init(nameString, director:String){
    5. self.director = director
    6. super.init(name: name)
    7. }
    8. }
    9. //歌曲类
    10. class Song: MediaItem {
    11. var airtist String
    12. init(nameString, airtistString{
    13. self.airtist = airtist
    14. super.init(name: name)
    15. }
    16. }

    最后一个创建一个数组常量library,包含两个Movie实例和三个Song实例,library的类型是在它被初始化时根据它数组中包含的内容推断来的,Swift的类型检测能够推断出Movie和Song有共同的父类MediaItem,所以推断出library的类型是MediaItem[],从library中取出的也是MediaItem类型,代码如下所示:

     
    1. //媒体数组
    2. let library /*: [MediaItem]*/ [
    3. Movie(name"星际穿越", director"Daniel"),
    4. Song(name"小苹果", airtist"筷子兄弟"),
    5. Movie(name"Breaking Bad", director"Guodh"),
    6. Song(name"最炫民族风", airtist"凤凰传奇"),
    7. Song(name"菊花台", airtist"Jay")
    8. ]

    步骤二:检测类型

    定义两个变量movieCount和songCount,用来计算数组library中Movie和Song类型的实例数量。

    遍历数组library中的每一个实例,使用is操作符判断类型,代码如下所示:

     
    1. //电影多少部?歌曲多少首
    2. var movieCount 0
    3. var songCount 0
    4. //is用于判断引用指向的对象是否是指定类型
    5. for item in library {
    6. if item is Movie {
    7. movieCount++
    8. }else if item is Song {
    9. songCount++
    10. }
    11. }
    12. movieCount
    13. songCount

    运行结果如图-1所示:

    图-1

    步骤三:转换类型

    遍历library里的每一个MediaItem实例,并打印出适当的描述,item需要真正作为Movie或Song的类型来使用,这是需要使用as操作符进行类型转换,代码如下所示:

     
    1. //遍历每个媒体,并打印详细信息
    2. for item in library {
    3. if item is Movie {
    4. //as用于强制装换,能转就转,不能转的话程序直接崩溃
    5. let movie = item as! Movie
    6. println("电影名:(movie.name),导演:(movie.director)")
    7. }else if item is Song {
    8. let song = item as! Song
    9. println("歌曲名:(song.name), 演唱者:(song.airtist)")
    10. }
    11. }

    但是数组中的每一个item可能是Movie或Song,所以这里使用可选类型的转换符更合适,代码如下所示:

     
    1. for item in library {
    2. //as?与as功能相同,能转就转,不能转返回nil,程序不会崩溃,返回的是一个可选值
    3. if let movie = item as? Movie {
    4. println("电影名:(movie.name),导演:(movie.director)")
    5. else if let song = item as? Song {
    6. println("歌曲名:(song.name), 演唱者:(song.airtist)")
    7. }
    8. }

    1.4 完整代码

    本案例中,完整代码如下所示:

     
    1. import UIKit
    2. //媒体类
    3. class MediaItem {
    4. var name String
    5. init(name:String){
    6. self.name = name
    7. }
    8. }
    9. //电影类
    10. class Movie : MediaItem {
    11. var director String
    12. init(nameString, director:String){
    13. self.director = director
    14. super.init(name: name)
    15. }
    16. }
    17. //歌曲类
    18. class Song: MediaItem {
    19. var airtist String
    20. init(nameString, airtistString{
    21. self.airtist = airtist
    22. super.init(name: name)
    23. }
    24. }
    25. //媒体数组
    26. let library /*: [MediaItem]*/ [
    27. Movie(name"星际穿越", director"Daniel"),
    28. Song(name"小苹果", airtist"筷子兄弟"),
    29. Movie(name"Breaking Bad", director"Guodh"),
    30. Song(name"最炫民族风", airtist"凤凰传奇"),
    31. Song(name"菊花台", airtist"Jay")
    32. ]
    33. //电影多少部?歌曲多少首
    34. var movieCount 0
    35. var songCount 0
    36. //is用于判断引用指向的对象是否是指定类型
    37. for item in library {
    38. if item is Movie {
    39. movieCount++
    40. }else if item is Song {
    41. songCount++
    42. }
    43. }
    44. movieCount
    45. songCount
    46. //遍历每个媒体,并打印详细信息
    47. for item in library {
    48. if item is Movie {
    49. //as用于强制装换,能转就转,不能转的话程序直接崩溃
    50. let movie = item as! Movie
    51. println("电影名:(movie.name),导演:(movie.director)")
    52. }else if item is Song {
    53. let song = item as! Song
    54. println("歌曲名:(song.name), 演唱者:(song.airtist)")
    55. }
    56. }
    57. for item in library {
    58. //as?与as功能相同,能转就转,不能转返回nil,程序不会崩溃,返回的是一个可选值
    59. if let movie = item as? Movie {
    60. println("电影名:(movie.name),导演:(movie.director)")
    61. else if let song = item as? Song {
    62. println("歌曲名:(song.name), 演唱者:(song.airtist)")
    63. }
    64. }
     

    2 扩展的使用

    2.1 问题

    扩展就是向一个已有的类、结构体或枚举添加新功能,和OC的分类类似。本案例演示Swift中扩展的用法,包括在扩展中添加计算属性、构造方法。实例方法和类型方法等。

    2.2 方案

    Swift中的扩展可以向已有的类型添加计算型实例属性和计算型类型属性,但是不可以添加存储属性,也不可以向已有属性添加属性观测器。

    扩展还可以向已有的类型添加新的构造器,新构造器有责任保证构造过程能够让所有属性全都初始化。对于类而言扩展只能添加新的便利构造器,不能添加新的指定构造器和析构方法,指定构造器和析构方法必须总是由原始的类提供。

    扩展可以向已有类型添加新的实例方法和类型方法。

    2.3 步骤

    实现此案例需要按照如下步骤进行。

    步骤一:添加计算型属性

    下面这个例子向已有的类型添加计算型属性,向Swift中的Double类型添加五个计算型实例属性,从而提供对距离单位的支持,这些属性都是可以通过点语法来访问。

    这些属性表达的含义是把一个Double类型的值看做是某单位下的长度值,1.0用来表示一米单位为m,其他单位则需要一些转换来表示在米下测量的值,km表示千米,ft表示英尺,cm表示厘米,mm表示毫米。

    这些属性都是只读的计算属性,所以可以省略get关键字,返回类型都是Double类型,代码如下所示:

    1. extension Double {
    2. var km:Double {
    3. return self*1000
    4. }
    5. var m:Double {
    6. return self
    7. }
    8. var cm:Double {
    9. return self/100
    10. }
    11. var mm:Double {
    12. return self/1000
    13. }
    14. var ft:Double {
    15. return self/3.28084
    16. }
    17. }
    18. let oneIch 25.4.mm
    19. let threeFeet 3.ft

    运行结果如图-2所示:

    图-2

    步骤二:添加构造方法

    定义一个用于描述几何矩形的定制结构体Rect,这个例子同时定义了两个辅助结构体Size和Point,0.0作为所有属性的默认值,代码如下所示:

     
    1. struct Point {
    2. var x 0.0
    3. var y 0.0
    4. }
    5. struct Size {
    6. var width 0.0
    7. var height 0.0
    8. }
    9. struct Rect {
    10. var origin Point()
    11. var size Size()
    12. }

    再使用扩展提供一个额外的构造器,可以使用中心点来进行构造,代码如下所示:

     
    1. extension Rect {
    2. init(center:Point,size:Size{
    3. var originX = center.x - size.width/2
    4. var originY = center.y - size.height/2
    5. self.origin Point(x: originX, y: originY)
    6. self.size = size
    7. }
    8. }
    9. var rect Rect(centerPoint(x20, y10), sizeSize(width10, height10))

    运行结果如图-3所示:

    图-3

    步骤三:添加方法

    向Int类型添加一个名为repetitions的新的实例方法,代码如下所示:

     
    1. extension Int {
    2. func repetition(task:()->()) {
    3. for i in 0...self {
    4. task()
    5. }
    6. }
    7. }
    8. var i 3
    9. i.repetition({println("hehe")})

    运行结果如图-4所示:

    图-4

    2.4 完整代码

    本案例中,完整代码如下所示:

     
    1. import UIKit
    2. //扩展计算属性
    3. extension Double {
    4. var km:Double {
    5. return self*1000
    6. }
    7. var m:Double {
    8. return self
    9. }
    10. var cm:Double {
    11. return self/100
    12. }
    13. var mm:Double {
    14. return self/1000
    15. }
    16. var ft:Double {
    17. return self/3.28084
    18. }
    19. }
    20. let oneIch 25.4.mm
    21. let threeFeet 3.ft
    22. //扩展构造器
    23. struct Point {
    24. var x 0.0
    25. var y 0.0
    26. }
    27. struct Size {
    28. var width 0.0
    29. var height 0.0
    30. }
    31. struct Rect {
    32. var origin Point()
    33. var size Size()
    34. }
    35. extension Rect {
    36. init(center:Point,size:Size{
    37. var originX = center.x - size.width/2
    38. var originY = center.y - size.height/2
    39. self.origin Point(x: originX, y: originY)
    40. self.size = size
    41. }
    42. }
    43. var rect Rect(centerPoint(x20, y10), sizeSize(width10, height10))
    44. //扩展方法
    45. extension Int {
    46. func repetition(task:()->()) {
    47. for i in 0...self {
    48. task()
    49. }
    50. }
    51. }
    52. var i 3
    53. 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的背景颜色设置为白色,代码如下所示:

     
    1. func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions[NSObject: AnyObject]?) -> Bool {
    2. // Override point for customization after application launch.
    3. self.window UIWindow(frame: UIScreen.mainScreen().bounds)
    4. //可选链,设置背景颜色
    5. self.window?.backgroundColor = UIColor.whiteColor()
    6. self.window?.makeKeyAndVisible()
    7. return true
    8. }

    然后创建window的根视图控制器,根视图控制器是ViewController类型,Swift项目中不需要导入头文件就可以使用项目中定义好的ViewController类,代码如下所示:

     
    1. func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions[NSObject: AnyObject]?) -> Bool {
    2. // Override point for customization after application launch.
    3. self.window UIWindow(frame: UIScreen.mainScreen().bounds)
    4. //可选链,设置背景颜色
    5. self.window?.backgroundColor = UIColor.whiteColor()
    6. //创建根视图控制器
    7. self.window?.rootViewController ViewController()
    8. self.window?.makeKeyAndVisible()
    9. return true
    10. }

    由上面的代码可以看出OC语言提供的类和方法完全可以在Swift中使用,只是换成Swift的语法而已,IOS程序的运行原理和开发思想与之前所学完全一致。

    步骤二:搭建界面

    计时器的界面上方是一个现实倒计时的Label控件,下方是一排预设的时间按钮,最下方是启动和复位按钮,首先将这些控件全都设置为ViewController的存储属性,在viewDidLoad方法中进行初始状态的设置,布局代码写在viewDidLayoutSubviews方法中,代码如下所示:

     
    1. class ViewController: UIViewController {
    2. var timeLabel:UILabel!
    3. var timeButtons:[UIButton]!
    4. var startButton:UIButton!
    5. var resetButton:UIButton!
    6. func setupTimeLabel(){
    7. timeLabel UILabel()
    8. timeLabel.textColor = UIColor.whiteColor()
    9. timeLabel.font = UIFont.boldSystemFontOfSize(80)
    10. timeLabel.backgroundColor = UIColor.blackColor()
    11. timeLabel.textAlignment = NSTextAlignment.Center
    12. view.addSubview(timeLabel)
    13. }
    14. //预设时间按钮的信息
    15. let timeButtonsInfo [("1min",60),("3min",180),("5min",300),("sec",1)]
    16. func setupTimeButtons(){
    17. timeButtons []
    18. for (title,secin timeButtonsInfo {
    19. let button UIButton()
    20. button.backgroundColor = UIColor.orangeColor()
    21. button.setTitle(title, forState:UIControlState.Normal)
    22. button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
    23. button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Highlighted)
    24. //记录对应的时间给tag
    25. button.tag = sec
    26. view.addSubview(button)
    27. timeButtons.append(button)
    28. }
    29. }
    30. func timeButtonTapped (button:UIButton){
    31. remainingSeconds = button.tag
    32. }
    33. //设置启动,复位按钮
    34. func setupActionButtons() {
    35. startButton UIButton()
    36. startButton.backgroundColor = UIColor.redColor()
    37. startButton.setTitleColor(UIColor.whiteColor(), forState.Normal)
    38. startButton.setTitleColor(UIColor.blackColor(), forState.Highlighted)
    39. startButton.setTitle("Start", forState.Normal)
    40. view.addSubview(startButton)
    41. resetButton UIButton()
    42. resetButton.backgroundColor = UIColor.redColor()
    43. resetButton.setTitleColor(UIColor.whiteColor(), forState.Normal)
    44. resetButton.setTitleColor(UIColor.blackColor(), forState.Highlighted)
    45. resetButton.setTitle("Reset", forState.Normal)
    46. view.addSubview(resetButton)
    47. }
    48. override func viewDidLoad() {
    49. super.viewDidLoad()
    50. setupTimeLabel()
    51. setupTimeButtons()
    52. setupActionButtons()
    53. }
    54. //布局代码
    55. override func viewDidLayoutSubviews() {
    56. //时间窗口的布局
    57. timeLabel.frame CGRect(x10, y40, width: view.bounds.size.width-20, height120)
    58. //时间按钮的布局:按钮大小:64x44,按钮之间的间隔
    59. let cnt = timeButtons.count 1
    60. let width = view.bounds.width 10*2.0 CGFloat(timeButtons.count64.0
    61. let gap width CGFloat(cnt)
    62. for (index, buttonin enumerate(timeButtons{
    63. let buttonLeft 10.0 CGFloat(index(64.0 + gap)
    64. button.frame CGRectMake(CGFloat(buttonLeft), view.bounds.height-120.06444)
    65. }
    66. //启动复位按钮的布局
    67. startButton.frame CGRectMake(10, view.bounds.height 60, view.bounds.width 20 10044)
    68. resetButton.frame CGRectMake(10 + startButton.frame.width+20, view.bounds.height 608044)
    69. }
    70. }

    运行程序完成的界面如图-9所示:

    图-9

    步骤三:实现计时功能

    首先设置一个记录当前剩余秒数的属性remainingSeconds,该属性是一个整型的计算属性,当remainingSeconds的值发生改变就更新timeLabel的显示内容,因此给该属性添加一个属性监视器,通过newValue计算出timeLabel显示的内容,代码如下所示:

     
    1. //计算剩余时间
    2. var remainingSeconds:Int {
    3. //属性监视器
    4. willSet {
    5. let min newValue/60
    6. let sec = newValue%60
    7. timeLabel.text String(NSString(format"%02d:%02d", min,sec))
    8. }
    9. }

    其次给预设时间按钮添加点击事件timeButtonTapped:,该方法将用户选择的时间秒数赋值给remainingSeconds,代码如下所示:

     
    1. //预设时间按钮的信息
    2. let timeButtonsInfo [("1min",60),("3min",180),("5min",300),("sec",1)]
    3. func setupTimeButtons(){
    4. timeButtons []
    5. for (title,secin timeButtonsInfo {
    6. let button UIButton()
    7. button.backgroundColor = UIColor.orangeColor()
    8. button.setTitle(title, forState:UIControlState.Normal)
    9. button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
    10. button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Highlighted)
    11. //记录对应的时间给tag
    12. button.tag = sec
    13. //给按钮添加点击事件
    14. button.addTarget(self, actionSelector("timeButtonTapped:"), forControlEvents: UIControlEvents.TouchUpInside)
    15. view.addSubview(button)
    16. timeButtons.append(button)
    17. }
    18. }
    19. func timeButtonTapped (button:UIButton){
    20. remainingSeconds += button.tag
    21. }

    然后给启动和复位按钮添加点击事件startButtonTapped:和resetButtonTapped:,代码如下所示:

     
    1. //设置启动,复位按钮
    2. func setupActionButtons() {
    3. startButton UIButton()
    4. startButton.backgroundColor = UIColor.redColor()
    5. startButton.setTitleColor(UIColor.whiteColor(), forState.Normal)
    6. startButton.setTitleColor(UIColor.blackColor(), forState.Highlighted)
    7. startButton.setTitle("Start", forState.Normal)
    8. view.addSubview(startButton)
    9. //添加事件
    10. startButton.addTarget(self, action"startButtonTapped:", forControlEvents.TouchUpInside)
    11. resetButton UIButton()
    12. resetButton.backgroundColor = UIColor.redColor()
    13. resetButton.setTitleColor(UIColor.whiteColor(), forState.Normal)
    14. resetButton.setTitleColor(UIColor.blackColor(), forState.Highlighted)
    15. resetButton.setTitle("Reset", forState.Normal)
    16. view.addSubview(resetButton)
    17. resetButton.addTarget(self, action"resetButtonTapped:", forControlEvents.TouchUpInside)
    18. }

    接下来需要实现startButtonTapped:和resetButtonTapped:方法,当点击启动按钮时计时器开始计时,因此需要开启一个timer。

    在实现startButtonTapped:和resetButtonTapped:方法之前需要在ViewController类中定义一个NSTimer类型的存储属性timer,以及一个用于记录当前计时状态的Bool类型的计算属性isCounting,并带有一个属性监视器。当isCounting属性值为true则表示当前处于计时状态,对timer进行初始化并开始计时,当isCounting属性值为false则表示当前停止计时,timer停止计时并清空,代码如下所示:

     
    1. //计时器计算属性
    2. var timer:NSTimer?
    3. var isCounting:Bool false {
    4. //添加属性监视器,当计时开始创建timer否则停止
    5. willSet {
    6. if newValue {
    7. timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selectorSelector("updateTimer:"), userInfo: nil, repeatstrue)
    8. }else {
    9. timer?.invalidate()
    10. timer = nil
    11. }
    12. setSettingButtonsEnabled(!newValue)
    13. }
    14. }
    15. //计时方法每一秒调用改变timeLable的显示,直到计时结束
    16. func updateTimer(timer:NSTimer){
    17. remainingSeconds--
    18. if remainingSeconds<={
    19. isCounting false
    20. var alertVC UIAlertController(title"时间到", message"", preferredStyle:.Alert)
    21. let action UIAlertAction(title"确定", style: UIAlertActionStyle.Default, handler(action-> Void in
    22. println("被按了")
    23. })
    24. alertVC.addAction(action)
    25. self.presentViewController(alertVC, animatedtrue, completion: nil)
    26. }
    27. }
    28. //打开或关闭设置时间的按钮
    29. func setSettingButtonsEnabled(enable:Bool{
    30. for button in timeButtons {
    31. button.enabled = enable
    32. button.alpha = enable ?1.0 0.3
    33. }
    34. resetButton.enabled = enable
    35. resetButton.alpha = enable ?1.0 0.3
    36. let title = enable "启动" "停止"
    37. startButton.setTitle(title, forState.Normal)
    38. }

    此时再实现startButtonTapped:和resetButtonTapped:方法,代码如下所示:

     
    1. func startButtonTapped(button:UIButton){
    2. isCounting !isCounting
    3. }
    4. func resetButtonTapped(){
    5. remainingSeconds 0
    6. }

    步骤四:后台计时,推送消息

    IOS8对程序的后台运行有很好的支持,当计时器退到后台,不用做任何操作就会自动后台计时,但是当计时完成用户并不知道计时已经完成,所以这个时候就需要使用IOS系统提供的本地消息推送功能,首先需要在程序加载成功的方法中请求用户同意接受消息推送,代码如下所示:

     
    1. func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions[NSObject: AnyObject]?) -> Bool {
    2. // Override point for customization after application launch.
    3. self.window UIWindow(frame: UIScreen.mainScreen().bounds)
    4. //可选链,设置背景颜色
    5. self.window?.backgroundColor = UIColor.whiteColor()
    6. self.window?.rootViewController ViewController()
    7. self.window?.makeKeyAndVisible()
    8. //请求用户获取消息推送权限
    9. let settings UIUserNotificationSettings(forTypes: UIUserNotificationType.Alert | UIUserNotificationType.Sound | UIUserNotificationType.Badge,categories: nil)
    10. application.registerUserNotificationSettings(settings)
    11. return true
    12. }

    其次从计时开始就添加消息推送,当计时完成时推送消息,代码如下所示:

     
    1. func startButtonTapped(button:UIButton){
    2. isCounting !isCounting
    3. if isCounting {
    4. //添加消息推送
    5. createAndFireLocalNotificationAfterSeconds(Double(remainingSeconds))
    6. }else {
    7. //计时结束退出消息推送
    8. UIApplication.sharedApplication().cancelAllLocalNotifications()
    9. }
    10. }
    11. //添加消息推送方法
    12. func createAndFireLocalNotificationAfterSeconds(seconds:NSTimeInterval{
    13. UIApplication.sharedApplication().cancelAllLocalNotifications()
    14. let notification UILocalNotification()
    15. //推送时间
    16. notification.fireDate NSDate(timeIntervalSinceNow: seconds)
    17. //推送时区
    18. notification.timeZone = NSTimeZone.systemTimeZone()
    19. //推送通知的内容
    20. notification.alertBody "Time is up!"
    21. UIApplication.sharedApplication().scheduleLocalNotification(notification)
    22. }

    运行程序消息推送效果如图-10所示:

    图-10

    3.4 完整代码

    本案例中,AppDelegate.swift文件中完整代码如下所示:

     
    1. import UIKit
    2. @UIApplicationMain
    3. class AppDelegate: UIResponder, UIApplicationDelegate {
    4. var window: UIWindow?
    5. func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions[NSObject: AnyObject]?) -> Bool {
    6. // Override point for customization after application launch.
    7. self.window UIWindow(frame: UIScreen.mainScreen().bounds)
    8. //可选链,设置背景颜色
    9. self.window?.backgroundColor = UIColor.whiteColor()
    10. self.window?.rootViewController ViewController()
    11. self.window?.makeKeyAndVisible()
    12. //请求用户获取消息推送权限
    13. let settings UIUserNotificationSettings(forTypes: UIUserNotificationType.Alert | UIUserNotificationType.Sound | UIUserNotificationType.Badge,categories: nil)
    14. application.registerUserNotificationSettings(settings)
    15. return true
    16. }
    17. }
     

    本案例中,ViewController.swift文件中完整代码如下所示:

     
    1. import UIKit
    2. class ViewController: UIViewController {
    3. var timeLabel:UILabel!
    4. var timeButtons:[UIButton]!
    5. var startButton:UIButton!
    6. var resetButton:UIButton!
    7. //计算剩余时间
    8. var remainingSeconds:Int {
    9. //属性监视器
    10. willSet {
    11. let min newValue/60
    12. let sec = newValue%60
    13. timeLabel.text String(NSString(format"%02d:%02d", min,sec))
    14. }
    15. }
    16. //计时器计算属性
    17. var timer:NSTimer?
    18. var isCounting:Bool false {
    19. //添加属性监视器,当计时开始创建timer否则停止
    20. willSet {
    21. if newValue {
    22. timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selectorSelector("updateTimer:"), userInfo: nil, repeatstrue)
    23. }else {
    24. timer?.invalidate()
    25. timer = nil
    26. }
    27. setSettingButtonsEnabled(!newValue)
    28. }
    29. }
    30. //计时方法每一秒调用改变timeLable的显示,直到计时结束
    31. func updateTimer(timer:NSTimer){
    32. remainingSeconds--
    33. if remainingSeconds<={
    34. isCounting false
    35. var alertVC UIAlertController(title"time is up", message"", preferredStyle:.Alert)
    36. let action UIAlertAction(title"Done", style: UIAlertActionStyle.Default, handler(action-> Void in
    37. println("被按了")
    38. })
    39. alertVC.addAction(action)
    40. self.presentViewController(alertVC, animatedtrue, completion: nil)
    41. }
    42. }
    43. //打开或关闭设置时间的按钮
    44. func setSettingButtonsEnabled(enable:Bool{
    45. for button in timeButtons {
    46. button.enabled = enable
    47. button.alpha = enable ?1.0 0.3
    48. }
    49. resetButton.enabled = enable
    50. resetButton.alpha = enable ?1.0 0.3
    51. let title = enable "Start" "Stop"
    52. startButton.setTitle(title, forState.Normal)
    53. }
    54. func setupTimeLabel(){
    55. timeLabel UILabel()
    56. timeLabel.textColor = UIColor.whiteColor()
    57. timeLabel.font = UIFont.boldSystemFontOfSize(80)
    58. timeLabel.backgroundColor = UIColor.blackColor()
    59. timeLabel.textAlignment = NSTextAlignment.Center
    60. view.addSubview(timeLabel)
    61. }
    62. //预设时间按钮的信息
    63. let timeButtonsInfo [("1min",60),("3min",180),("5min",300),("sec",1)]
    64. func setupTimeButtons(){
    65. timeButtons []
    66. for (title,secin timeButtonsInfo {
    67. let button UIButton()
    68. button.backgroundColor = UIColor.orangeColor()
    69. button.setTitle(title, forState:UIControlState.Normal)
    70. button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
    71. button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Highlighted)
    72. //记录对应的时间给tag
    73. button.tag = sec
    74. //给按钮添加点击事件
    75. button.addTarget(self, actionSelector("timeButtonTapped:"), forControlEvents: UIControlEvents.TouchUpInside)
    76. view.addSubview(button)
    77. timeButtons.append(button)
    78. }
    79. }
    80. func timeButtonTapped (button:UIButton){
    81. remainingSeconds += button.tag
    82. }
    83. //设置启动,复位按钮
    84. func setupActionButtons() {
    85. startButton UIButton()
    86. startButton.backgroundColor = UIColor.redColor()
    87. startButton.setTitleColor(UIColor.whiteColor(), forState.Normal)
    88. startButton.setTitleColor(UIColor.blackColor(), forState.Highlighted)
    89. startButton.setTitle("Start", forState.Normal)
    90. view.addSubview(startButton)
    91. //添加事件
    92. startButton.addTarget(self, action"startButtonTapped:", forControlEvents.TouchUpInside)
    93. resetButton UIButton()
    94. resetButton.backgroundColor = UIColor.redColor()
    95. resetButton.setTitleColor(UIColor.whiteColor(), forState.Normal)
    96. resetButton.setTitleColor(UIColor.blackColor(), forState.Highlighted)
    97. resetButton.setTitle("Reset", forState.Normal)
    98. view.addSubview(resetButton)
    99. resetButton.addTarget(self, action"resetButtonTapped:", forControlEvents.TouchUpInside)
    100. }
    101. func startButtonTapped(button:UIButton){
    102. isCounting !isCounting
    103. if isCounting {
    104. //添加消息推送
    105. createAndFireLocalNotificationAfterSeconds(Double(remainingSeconds))
    106. }else {
    107. //计时结束退出消息推送
    108. UIApplication.sharedApplication().cancelAllLocalNotifications()
    109. }
    110. }
    111. func resetButtonTapped(button:UIButton){
    112. remainingSeconds 0
    113. }
    114. //添加消息推送方法
    115. func createAndFireLocalNotificationAfterSeconds(seconds:NSTimeInterval{
    116. //取消之前所有的消息推送
    117. UIApplication.sharedApplication().cancelAllLocalNotifications()
    118. let notification UILocalNotification()
    119. //推送时间
    120. notification.fireDate NSDate(timeIntervalSinceNow: seconds)
    121. //推送时区
    122. notification.timeZone = NSTimeZone.systemTimeZone()
    123. //推送通知的内容
    124. notification.alertBody "Time is up!"
    125. UIApplication.sharedApplication().scheduleLocalNotification(notification)
    126. }
    127. override func viewDidLoad() {
    128. super.viewDidLoad()
    129. setupTimeLabel()
    130. setupTimeButtons()
    131. setupActionButtons()
    132. }
    133. //布局代码
    134. override func viewDidLayoutSubviews() {
    135. //时间窗口的布局
    136. timeLabel.frame CGRect(x10, y40, width: view.bounds.size.width-20, height120)
    137. //时间按钮的布局:按钮大小:64x44,按钮之间的间隔
    138. let cnt = timeButtons.count 1
    139. let width = view.bounds.width 10*2.0 CGFloat(timeButtons.count64.0
    140. let gap width CGFloat(cnt)
    141. for (index, buttonin enumerate(timeButtons{
    142. let buttonLeft 10.0 CGFloat(index(64.0 + gap)
    143. button.frame CGRectMake(CGFloat(buttonLeft), view.bounds.height-120.06444)
    144. }
    145. //启动复位按钮的布局
    146. startButton.frame CGRectMake(10, view.bounds.height 60, view.bounds.width 20 10044)
    147. resetButton.frame CGRectMake(10 + startButton.frame.width+20, view.bounds.height 608044)
    148. }
    149. }
     
  • 相关阅读:
    oracelp---随意 记录(nvl)
    delphi小知识 点(if条件符,to_date)
    截取字符(pos,copy,Leftstr,MidStr,RightStr)以逗号为准把字符串拆分,判断字符串是否有数字、字母(大小写), 去掉字符串空格
    js HTML DOM TableRow 对象(innerHTML)
    mysql 安装相关
    初识JAVAScript
    css
    css深入
    css的学习
    前端 html
  • 原文地址:https://www.cnblogs.com/hytx/p/5053772.html
Copyright © 2020-2023  润新知