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(name: String, director:String){
  5. self.director = director
  6. super.init(name: name)
  7. }
  8. }
  9. //歌曲类
  10. class Song: MediaItem {
  11. var airtist : String
  12. init(name: String, airtist: String) {
  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(name: String, director:String){
  13. self.director = director
  14. super.init(name: name)
  15. }
  16. }
  17. //歌曲类
  18. class Song: MediaItem {
  19. var airtist : String
  20. init(name: String, airtist: String) {
  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(center: Point(x: 20, y: 10), size: Size(width: 10, height: 10))

运行结果如图-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(center: Point(x: 20, y: 10), size: Size(width: 10, height: 10))
  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,sec) in 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(x: 10, y: 40, width: view.bounds.size.width-20, height: 120)
  58. //时间按钮的布局:按钮大小:64x44,按钮之间的间隔
  59. let cnt = timeButtons.count - 1
  60. let width = view.bounds.width - 10*2.0 - CGFloat(timeButtons.count) * 64.0
  61. let gap = width / CGFloat(cnt)
  62. for (index, button) in enumerate(timeButtons) {
  63. let buttonLeft = 10.0 + CGFloat(index) * (64.0 + gap)
  64. button.frame = CGRectMake(CGFloat(buttonLeft), view.bounds.height-120.0, 64, 44)
  65. }
  66. //启动复位按钮的布局
  67. startButton.frame = CGRectMake(10, view.bounds.height - 60, view.bounds.width - 20 - 100, 44)
  68. resetButton.frame = CGRectMake(10 + startButton.frame.width+20, view.bounds.height - 60, 80, 44)
  69. }
  70. }

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

图-9

步骤三:实现计时功能

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

  1. //计算剩余时间
  2. var remainingSeconds:Int = 0 {
  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,sec) in 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, action: Selector("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, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)
  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<=0 {
  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, animated: true, 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 = 0 {
  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, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)
  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<=0 {
  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, animated: true, 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,sec) in 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, action: Selector("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(x: 10, y: 40, width: view.bounds.size.width-20, height: 120)
  137. //时间按钮的布局:按钮大小:64x44,按钮之间的间隔
  138. let cnt = timeButtons.count - 1
  139. let width = view.bounds.width - 10*2.0 - CGFloat(timeButtons.count) * 64.0
  140. let gap = width / CGFloat(cnt)
  141. for (index, button) in enumerate(timeButtons) {
  142. let buttonLeft = 10.0 + CGFloat(index) * (64.0 + gap)
  143. button.frame = CGRectMake(CGFloat(buttonLeft), view.bounds.height-120.0, 64, 44)
  144. }
  145. //启动复位按钮的布局
  146. startButton.frame = CGRectMake(10, view.bounds.height - 60, view.bounds.width - 20 - 100, 44)
  147. resetButton.frame = CGRectMake(10 + startButton.frame.width+20, view.bounds.height - 60, 80, 44)
  148. }
  149. }
				
时间: 2024-10-11 05:43:05

Swift-----类型转换 、 嵌套类型 、 扩展 、 协议 、 访问控制的相关文章

Swift的可选链,类型转换和扩展

可选链(Optional Chaining) 可选链是一种请求或调用属性,方法,子脚本的过程. 可选性体现于请求或调用的目标当前可能为nil.若不为nil则成功调用,否则返回nil并将链失效. 调用可选链的返回结果与原结果类型相同,但是被包装成为了一个可选类型Optional. 这里由于roomCount返回为nil 所以执行else语句为count赋值为-1. 标注:在Beta3版本发布时对Swift稍微进行了修改,nil变成了关键字,而不再存在NilType的nil了. 可选链可以连续多层调

Swift中文教程(七)--协议,扩展和泛型

Protocols and Extensions 协议(接口)和扩展 Swift使用关键字protocol声明一个协议(接口): 类(classes),枚举(enumerations)和结构(structs)都可采用协议(protocol): 1 class SimpleClass: ExampleProtocol { 2 var simpleDescription: String = "A very simple class." 3 var anotherProperty: Int

五 Swift开发之扩展(Extension)

五 Swift开发之扩展(Extensions) //扩展就是向一个已有的类.结构体或枚举类型添加新功能(functionality).这包括在没有权限获取原始源代码的情况下扩展类型的能力(即逆向建模).扩展和 Objective-C 中的分类(categories)类似.(不过与Objective-C不同的是,Swift 的扩展没有名字.) Swift 中的扩展可以: 1.添加计算型属性和计算静态属性 2.定义实例方法和类型方法 3.提供新的构造器 4.定义下标 5.定义和使用新的嵌套类型 6

swift开发之--Protocol(协议)

使用object-c语言的同学们肯定对协议都不陌生,但在swift中苹果将protocol这种语法发扬的更加深入和彻底. Swift中的protocol不仅能定义方法还能定义属性,配合extension扩展的使用还能提供一些方法的默认实现,而且不仅类可以遵循协议,现在的枚举和结构体也能遵循协议了. 基于此本文从 : 1,协议中定义属性和方法, 2,协议的继承.聚合.关联类型, 3,协议的扩展, 4,Swift标准库中常见的协议, 5,为什么要使用协议 5个方面结合自身的学习经验简单介绍一下这种"

IOS开发语言Swift入门连载---扩展

IOS开发语言Swift入门连载-扩展 扩展就是向一个已有的类.结构体或枚举类型添加新功能(functionality).这包括在没有权限获取原始源代码的情况下扩展类型的能力(即逆向建模).扩展和 Objective-C 中的分类(categories)类似.(不过与Objective-C不同的是,Swift 的扩展没有名字.) Swift中的扩展可以: 添加计算型属性和计算静态属性 定义实例方法和类型方法 提供新的构造器 定义下标 定义和使用新的嵌套类型 使一个已有类型符合某个协议 注意: 如

Swift 学习笔记(面向协议编程)

在Swift中协议不仅可以定义方法和属性,而且协议是可以扩展的,最关键的是,在协议的扩展中可以添加一些方法的默认实现,就是在协议的方法中可以实现一些逻辑,由于这个特性,Swift是可以面向协议进行编程的. 扩展协议和默认实现 protocol Record { var wins: Int{get} var losses:Int{get} func winningPercent() -> Double } struct BasketballRecord:Record,CustomStringCon

Packet Tracer 5.2实验(十三) 扩展IP访问控制列表配置

Packet Tracer 5.2实验(十三) 扩展IP访问控制列表配置 一.实验目标 理解扩展IP访问控制列表的原理及功能: 掌握编号的扩展IP访问控制列表的配置方法: 二.实验背景 分公司和总公司分别属于不同的网段,部门之间用路由器进行信息传递,为了安全起见,分公司领导要求部门主机只能访问总公司服务器的WWW服务,不能对其使用ICMP服务. 三.技术原理 访问列表中定义的典型规则主要有以下:源地址.目标地址.上层协议.时间区域: 扩展IP访问列表(编号为100~199,2000~2699)使

Dubbo之旅--扩展协议

在实际工作中运用dubbo的时候,以上系列的文章基本上能够满足项目的基本需求,当然,对于一些特殊的需求Dubbo可以对其进行扩展,Dubbo拥有者丰富的扩展内容,这次主要将会带领大家去感受一下Dubbo的协议扩展和注册中心扩展. 首先要说的是协议扩展. 为什么要扩展协议呢?什么样的需求需要我们去扩展它? (1) 不同服务不同协议 需求:不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议. consumer.xml <?xmlversion="1.0&qu

swift 笔记 (十九) —— 协议

协议(Protocols) 协议仅是用定义某些任务或者是功能必须的方法和属性.类似于java里的interface的作用.但协议并不会实现具体的功能. 我猜这个名字源于OO中提到的"契约",但我并不觉得这名字很好,反而是interface这名字更容被接受,因为我觉得协议这个名字很容易和网络编程的时候的网络协议搞混,网络协议也通常简称为协议. 语法: protocol MyProtocol { //协议定义 } struct MyStruct: MyProtocol1, MyProtoc

第十四章 扩展IP访问控制列表配置

一.实验名称 扩展IP访问控制列表配置 二.实验内容 1.新建 Packet Tracer 拓扑图. 2.路由器R1与路由器R2通过 V.35 电缆串口连接,DCE 端连接在 R2 上, 配置其时钟频率 64000: 主机与路由器通过交叉线连接. 3.配置PC 机.服务器及路由器接口 IP 地址. 4.在各路由器上配置静态路由协议,让 PC 间能相互 ping 通,因为只有在互通的前 提下才涉及到访问控制列表. 5.在 R2 上配置编号的 IP 扩展访问控制列表. 6.将扩展 IP 访问列表应用