1. 使用isas操作符判断和转换数组中的对象类型
  2.  
  3. 1.1 问题
  4.  
  5. 类型转换可以判断实例的类型,也可以将实例看做是其父类或者子类的实例。在Swift中使用isas操作符实现类型转换。
  6.  
  7. 本案例定义一个媒体类MediaItem,它有两个子类MovieSong,创建一个存放Movie实例和Song实例的媒体数组library,使用isas操作符判断和转化library数组中的实例类型。
  8.  
  9. 1.2 方案
  10.  
  11. 使用类型检查操作符is来检查一个实例是否属于特定子类型,如果属于该子类型操作符返回true,否则返回false
  12.  
  13. 某类型的一个常量或变量可能实际上属于某一个子类,使用类型转换操作符as可以将其转换成子类型。转换过程可能会失败,因此类型转换操作符有两种不同的形式,可选形式as?和强制形式as
  14.  
  15. 1.3 步骤
  16.  
  17. 实现此案例需要按照如下步骤进行。
  18.  
  19. 步骤一:定义MediaItem
  20.  
  21. 首先定义一个MediaItem媒体类,包含一个String类型的name属性,和一个init构造方法,代码如下所示:
  22.  
  23. //媒体类
  24. class MediaItem {
  25. var name : String
  26. init(name:String){
  27. self.name = name
  28. }
  29. }
  30. 然后定义MediaItem的两个子类,第一个子类Movie在父类的基础上增加一个director属性,和相应的构造方法。第二个子类Song,在父类的基础上增加了一个artist属性,和相应的构造方法,代码如下所示:
  31.  
  32. //电影类
  33. class Movie : MediaItem {
  34. var director : String
  35. init(name: String, director:String){
  36. self.director = director
  37. super.init(name: name)
  38. }
  39. }
  40. //歌曲类
  41. class Song: MediaItem {
  42. var airtist : String
  43. init(name: String, airtist: String) {
  44. self.airtist = airtist
  45. super.init(name: name)
  46. }
  47. }
  48. 最后一个创建一个数组常量library,包含两个Movie实例和三个Song实例,library的类型是在它被初始化时根据它数组中包含的内容推断来的,Swift的类型检测能够推断出MovieSong有共同的父类MediaItem,所以推断出library的类型是MediaItem[],从library中取出的也是MediaItem类型,代码如下所示:
  49.  
  50. //媒体数组
  51. let library /*: [MediaItem]*/ = [
  52. Movie(name: "星际穿越", director: "Daniel"),
  53. Song(name: "小苹果", airtist: "筷子兄弟"),
  54. Movie(name: "Breaking Bad", director: "Guodh"),
  55. Song(name: "最炫民族风", airtist: "凤凰传奇"),
  56. Song(name: "菊花台", airtist: "Jay")
  57. ]
  58. 步骤二:检测类型
  59.  
  60. 定义两个变量movieCountsongCount,用来计算数组libraryMovieSong类型的实例数量。
  61.  
  62. 遍历数组library中的每一个实例,使用is操作符判断类型,代码如下所示:
  63.  
  64. //电影多少部?歌曲多少首
  65. var movieCount =
  66. var songCount =
  67. //is用于判断引用指向的对象是否是指定类型
  68. for item in library {
  69. if item is Movie {
  70. movieCount++
  71. }else if item is Song {
  72. songCount++
  73. }
  74. }
  75. movieCount
  76. songCount
  77. 运行结果如图-1所示:
  78.  
  79. 图-
  80.  
  81. 步骤三:转换类型
  82.  
  83. 遍历library里的每一个MediaItem实例,并打印出适当的描述,item需要真正作为MovieSong的类型来使用,这是需要使用as操作符进行类型转换,代码如下所示:
  84.  
  85. //遍历每个媒体,并打印详细信息
  86. for item in library {
  87. if item is Movie {
  88. //as用于强制装换,能转就转,不能转的话程序直接崩溃
  89. let movie = item as! Movie
  90. println("电影名:\(movie.name),导演:\(movie.director)")
  91. }else if item is Song {
  92. let song = item as! Song
  93. println("歌曲名:\(song.name), 演唱者:\(song.airtist)")
  94. }
  95. }
  96. 但是数组中的每一个item可能是MovieSong,所以这里使用可选类型的转换符更合适,代码如下所示:
  97.  
  98. for item in library {
  99. //as?与as功能相同,能转就转,不能转返回nil,程序不会崩溃,返回的是一个可选值
  100. if let movie = item as? Movie {
  101. println("电影名:\(movie.name),导演:\(movie.director)")
  102. } else if let song = item as? Song {
  103. println("歌曲名:\(song.name), 演唱者:\(song.airtist)")
  104. }
  105. }
  106. 1.4 完整代码
  107.  
  108. 本案例中,完整代码如下所示:
  109.  
  110. import UIKit
  111. //媒体类
  112. class MediaItem {
  113. var name : String
  114. init(name:String){
  115. self.name = name
  116. }
  117. }
  118. //电影类
  119. class Movie : MediaItem {
  120. var director : String
  121. init(name: String, director:String){
  122. self.director = director
  123. super.init(name: name)
  124. }
  125. }
  126. //歌曲类
  127. class Song: MediaItem {
  128. var airtist : String
  129. init(name: String, airtist: String) {
  130. self.airtist = airtist
  131. super.init(name: name)
  132. }
  133. }
  134. //媒体数组
  135. let library /*: [MediaItem]*/ = [
  136. Movie(name: "星际穿越", director: "Daniel"),
  137. Song(name: "小苹果", airtist: "筷子兄弟"),
  138. Movie(name: "Breaking Bad", director: "Guodh"),
  139. Song(name: "最炫民族风", airtist: "凤凰传奇"),
  140. Song(name: "菊花台", airtist: "Jay")
  141. ]
  142. //电影多少部?歌曲多少首
  143. var movieCount =
  144. var songCount =
  145. //is用于判断引用指向的对象是否是指定类型
  146. for item in library {
  147. if item is Movie {
  148. movieCount++
  149. }else if item is Song {
  150. songCount++
  151. }
  152. }
  153. movieCount
  154. songCount
  155. //遍历每个媒体,并打印详细信息
  156. for item in library {
  157. if item is Movie {
  158. //as用于强制装换,能转就转,不能转的话程序直接崩溃
  159. let movie = item as! Movie
  160. println("电影名:\(movie.name),导演:\(movie.director)")
  161. }else if item is Song {
  162. let song = item as! Song
  163. println("歌曲名:\(song.name), 演唱者:\(song.airtist)")
  164. }
  165. }
  166. for item in library {
  167. //as?与as功能相同,能转就转,不能转返回nil,程序不会崩溃,返回的是一个可选值
  168. if let movie = item as? Movie {
  169. println("电影名:\(movie.name),导演:\(movie.director)")
  170. } else if let song = item as? Song {
  171. println("歌曲名:\(song.name), 演唱者:\(song.airtist)")
  172. }
  173. }
  174.  
  175. 扩展的使用
  176.  
  177. 2.1 问题
  178.  
  179. 扩展就是向一个已有的类、结构体或枚举添加新功能,和OC的分类类似。本案例演示Swift中扩展的用法,包括在扩展中添加计算属性、构造方法。实例方法和类型方法等。
  180.  
  181. 2.2 方案
  182.  
  183. Swift中的扩展可以向已有的类型添加计算型实例属性和计算型类型属性,但是不可以添加存储属性,也不可以向已有属性添加属性观测器。
  184.  
  185. 扩展还可以向已有的类型添加新的构造器,新构造器有责任保证构造过程能够让所有属性全都初始化。对于类而言扩展只能添加新的便利构造器,不能添加新的指定构造器和析构方法,指定构造器和析构方法必须总是由原始的类提供。
  186.  
  187. 扩展可以向已有类型添加新的实例方法和类型方法。
  188.  
  189. 2.3 步骤
  190.  
  191. 实现此案例需要按照如下步骤进行。
  192.  
  193. 步骤一:添加计算型属性
  194.  
  195. 下面这个例子向已有的类型添加计算型属性,向Swift中的Double类型添加五个计算型实例属性,从而提供对距离单位的支持,这些属性都是可以通过点语法来访问。
  196.  
  197. 这些属性表达的含义是把一个Double类型的值看做是某单位下的长度值,.0用来表示一米单位为m,其他单位则需要一些转换来表示在米下测量的值,km表示千米,ft表示英尺,cm表示厘米,mm表示毫米。
  198.  
  199. 这些属性都是只读的计算属性,所以可以省略get关键字,返回类型都是Double类型,代码如下所示:
  200.  
  201. extension Double {
  202. var km:Double {
  203. return self*
  204. }
  205. var m:Double {
  206. return self
  207. }
  208. var cm:Double {
  209. return self/
  210. }
  211. var mm:Double {
  212. return self/
  213. }
  214. var ft:Double {
  215. return self/3.28084
  216. }
  217. }
  218. let oneIch = 25.4.mm
  219. let threeFeet = .ft
  220. 运行结果如图-2所示:
  221.  
  222. 图-
  223.  
  224. 步骤二:添加构造方法
  225.  
  226. 定义一个用于描述几何矩形的定制结构体Rect,这个例子同时定义了两个辅助结构体SizePoint,.0作为所有属性的默认值,代码如下所示:
  227.  
  228. struct Point {
  229. var x = 0.0
  230. var y = 0.0
  231. }
  232. struct Size {
  233. var width = 0.0
  234. var height = 0.0
  235. }
  236. struct Rect {
  237. var origin = Point()
  238. var size = Size()
  239. }
  240. 再使用扩展提供一个额外的构造器,可以使用中心点来进行构造,代码如下所示:
  241.  
  242. extension Rect {
  243. init(center:Point,size:Size) {
  244. var originX = center.x - size.width/
  245. var originY = center.y - size.height/
  246. self.origin = Point(x: originX, y: originY)
  247. self.size = size
  248. }
  249. }
  250. var rect = Rect(center: Point(x: , y: ), size: Size(width: , height: ))
  251. 运行结果如图-3所示:
  252.  
  253. 图-
  254.  
  255. 步骤三:添加方法
  256.  
  257. Int类型添加一个名为repetitions的新的实例方法,代码如下所示:
  258.  
  259. extension Int {
  260. func repetition(task:()->()) {
  261. for i in ...self {
  262. task()
  263. }
  264. }
  265. }
  266. var i =
  267. i.repetition({println("hehe")})
  268. 运行结果如图-4所示:
  269.  
  270. 图-
  271.  
  272. 2.4 完整代码
  273.  
  274. 本案例中,完整代码如下所示:
  275.  
  276. import UIKit
  277. //扩展计算属性
  278. extension Double {
  279. var km:Double {
  280. return self*
  281. }
  282. var m:Double {
  283. return self
  284. }
  285. var cm:Double {
  286. return self/
  287. }
  288. var mm:Double {
  289. return self/
  290. }
  291. var ft:Double {
  292. return self/3.28084
  293. }
  294. }
  295. let oneIch = 25.4.mm
  296. let threeFeet = .ft
  297. //扩展构造器
  298. struct Point {
  299. var x = 0.0
  300. var y = 0.0
  301. }
  302. struct Size {
  303. var width = 0.0
  304. var height = 0.0
  305. }
  306. struct Rect {
  307. var origin = Point()
  308. var size = Size()
  309. }
  310. extension Rect {
  311. init(center:Point,size:Size) {
  312. var originX = center.x - size.width/
  313. var originY = center.y - size.height/
  314. self.origin = Point(x: originX, y: originY)
  315. self.size = size
  316. }
  317. }
  318. var rect = Rect(center: Point(x: , y: ), size: Size(width: , height: ))
  319. //扩展方法
  320. extension Int {
  321. func repetition(task:()->()) {
  322. for i in ...self {
  323. task()
  324. }
  325. }
  326. }
  327. var i =
  328. repetition({println("hehe")})
  329.  
  330. 计时器
  331.  
  332. 3.1 问题
  333.  
  334. 本案例学习使用Swift语言使用纯代码的方式实现第一个Swift项目——一个简单的计时器,如图-,图-6所示:
  335.  
  336. 图-
  337.  
  338. 图-
  339.  
  340. 3.2 方案
  341.  
  342. 首先使用Xcode创建一个SingleViewApplication项目,编程语言选择Swift,可以看到Xcode已经提供的项目代码全都换成Swift语言实现,如图-7所示:
  343.  
  344. 图-
  345.  
  346. 本案例采用纯代码的方式实现所以删除Storyboard,将程序的MainInterface清空,在程序的启动方法中,采用手写代码的方式创建的window,如图-8所示:
  347.  
  348. 图-
  349.  
  350. 接下来使用代码搭建计时器项目的界面,界面上方是一个现实倒计时的Label控件,下方是一排预设的时间按钮,最下方是启动和复位按钮。
  351.  
  352. 扩展可以向已有类型添加新的实例方法和类型方法。
  353.  
  354. 3.3 步骤
  355.  
  356. 实现此案例需要按照如下步骤进行。
  357.  
  358. 步骤一:创建window对象和根视图控制器
  359.  
  360. 首先在AppDeleagte类中程序加载完成的方法中创建一个和屏幕大小一样的window对象,并将window的背景颜色设置为白色,代码如下所示:
  361.  
  362. func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  363. // Override point for customization after application launch.
  364. self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
  365. //可选链,设置背景颜色
  366. self.window?.backgroundColor = UIColor.whiteColor()
  367. self.window?.makeKeyAndVisible()
  368. return true
  369. }
  370. 然后创建window的根视图控制器,根视图控制器是ViewController类型,Swift项目中不需要导入头文件就可以使用项目中定义好的ViewController类,代码如下所示:
  371.  
  372. func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  373. // Override point for customization after application launch.
  374. self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
  375. //可选链,设置背景颜色
  376. self.window?.backgroundColor = UIColor.whiteColor()
  377. //创建根视图控制器
  378. self.window?.rootViewController = ViewController()
  379. self.window?.makeKeyAndVisible()
  380. return true
  381. }
  382. 由上面的代码可以看出OC语言提供的类和方法完全可以在Swift中使用,只是换成Swift的语法而已,IOS程序的运行原理和开发思想与之前所学完全一致。
  383.  
  384. 步骤二:搭建界面
  385.  
  386. 计时器的界面上方是一个现实倒计时的Label控件,下方是一排预设的时间按钮,最下方是启动和复位按钮,首先将这些控件全都设置为ViewController的存储属性,在viewDidLoad方法中进行初始状态的设置,布局代码写在viewDidLayoutSubviews方法中,代码如下所示:
  387.  
  388. class ViewController: UIViewController {
  389. var timeLabel:UILabel!
  390. var timeButtons:[UIButton]!
  391. var startButton:UIButton!
  392. var resetButton:UIButton!
  393. func setupTimeLabel(){
  394. timeLabel = UILabel()
  395. timeLabel.textColor = UIColor.whiteColor()
  396. timeLabel.font = UIFont.boldSystemFontOfSize()
  397. timeLabel.backgroundColor = UIColor.blackColor()
  398. timeLabel.textAlignment = NSTextAlignment.Center
  399. view.addSubview(timeLabel)
  400. }
  401. //预设时间按钮的信息
  402. let timeButtonsInfo = [("1min",),("3min",),("5min",),("sec",)]
  403. func setupTimeButtons(){
  404. timeButtons = []
  405. for (title,sec) in timeButtonsInfo {
  406. let button = UIButton()
  407. button.backgroundColor = UIColor.orangeColor()
  408. button.setTitle(title, forState:UIControlState.Normal)
  409. button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
  410. button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Highlighted)
  411. //记录对应的时间给tag
  412. button.tag = sec
  413. view.addSubview(button)
  414. timeButtons.append(button)
  415. }
  416. }
  417. func timeButtonTapped (button:UIButton){
  418. remainingSeconds = button.tag
  419. }
  420. //设置启动,复位按钮
  421. func setupActionButtons() {
  422. startButton = UIButton()
  423. startButton.backgroundColor = UIColor.redColor()
  424. startButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
  425. startButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
  426. startButton.setTitle("Start", forState: .Normal)
  427. view.addSubview(startButton)
  428. resetButton = UIButton()
  429. resetButton.backgroundColor = UIColor.redColor()
  430. resetButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
  431. resetButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
  432. resetButton.setTitle("Reset", forState: .Normal)
  433. view.addSubview(resetButton)
  434. }
  435. override func viewDidLoad() {
  436. super.viewDidLoad()
  437. setupTimeLabel()
  438. setupTimeButtons()
  439. setupActionButtons()
  440. }
  441. //布局代码
  442. override func viewDidLayoutSubviews() {
  443. //时间窗口的布局
  444. timeLabel.frame = CGRect(x: , y: , width: view.bounds.size.width-, height: )
  445. //时间按钮的布局:按钮大小:64x44,按钮之间的间隔
  446. let cnt = timeButtons.count -
  447. let width = view.bounds.width - *2.0 - CGFloat(timeButtons.count) * 64.0
  448. let gap = width / CGFloat(cnt)
  449. for (index, button) in enumerate(timeButtons) {
  450. let buttonLeft = 10.0 + CGFloat(index) * (64.0 + gap)
  451. button.frame = CGRectMake(CGFloat(buttonLeft), view.bounds.height-120.0, , )
  452. }
  453. //启动复位按钮的布局
  454. startButton.frame = CGRectMake(, view.bounds.height - , view.bounds.width - - , )
  455. resetButton.frame = CGRectMake( + startButton.frame.width+, view.bounds.height - , , )
  456. }
  457. }
  458. 运行程序完成的界面如图-9所示:
  459.  
  460. 图-
  461.  
  462. 步骤三:实现计时功能
  463.  
  464. 首先设置一个记录当前剩余秒数的属性remainingSeconds,该属性是一个整型的计算属性,当remainingSeconds的值发生改变就更新timeLabel的显示内容,因此给该属性添加一个属性监视器,通过newValue计算出timeLabel显示的内容,代码如下所示:
  465.  
  466. //计算剩余时间
  467. var remainingSeconds:Int = {
  468. //属性监视器
  469. willSet {
  470. let min = newValue/
  471. let sec = newValue%
  472. timeLabel.text = String(NSString(format: "%02d:%02d", min,sec))
  473. }
  474. }
  475. 其次给预设时间按钮添加点击事件timeButtonTapped:,该方法将用户选择的时间秒数赋值给remainingSeconds,代码如下所示:
  476.  
  477. //预设时间按钮的信息
  478. let timeButtonsInfo = [("1min",),("3min",),("5min",),("sec",)]
  479. func setupTimeButtons(){
  480. timeButtons = []
  481. for (title,sec) in timeButtonsInfo {
  482. let button = UIButton()
  483. button.backgroundColor = UIColor.orangeColor()
  484. button.setTitle(title, forState:UIControlState.Normal)
  485. button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
  486. button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Highlighted)
  487. //记录对应的时间给tag
  488. button.tag = sec
  489. //给按钮添加点击事件
  490. button.addTarget(self, action: Selector("timeButtonTapped:"), forControlEvents: UIControlEvents.TouchUpInside)
  491. view.addSubview(button)
  492. timeButtons.append(button)
  493. }
  494. }
  495. func timeButtonTapped (button:UIButton){
  496. remainingSeconds += button.tag
  497. }
  498. 然后给启动和复位按钮添加点击事件startButtonTapped:和resetButtonTapped:,代码如下所示:
  499.  
  500. //设置启动,复位按钮
  501. func setupActionButtons() {
  502. startButton = UIButton()
  503. startButton.backgroundColor = UIColor.redColor()
  504. startButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
  505. startButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
  506. startButton.setTitle("Start", forState: .Normal)
  507. view.addSubview(startButton)
  508. //添加事件
  509. startButton.addTarget(self, action: "startButtonTapped:", forControlEvents: .TouchUpInside)
  510. resetButton = UIButton()
  511. resetButton.backgroundColor = UIColor.redColor()
  512. resetButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
  513. resetButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
  514. resetButton.setTitle("Reset", forState: .Normal)
  515. view.addSubview(resetButton)
  516. resetButton.addTarget(self, action: "resetButtonTapped:", forControlEvents: .TouchUpInside)
  517. }
  518. 接下来需要实现startButtonTapped:和resetButtonTapped:方法,当点击启动按钮时计时器开始计时,因此需要开启一个timer
  519.  
  520. 在实现startButtonTapped:和resetButtonTapped:方法之前需要在ViewController类中定义一个NSTimer类型的存储属性timer,以及一个用于记录当前计时状态的Bool类型的计算属性isCounting,并带有一个属性监视器。当isCounting属性值为true则表示当前处于计时状态,对timer进行初始化并开始计时,当isCounting属性值为false则表示当前停止计时,timer停止计时并清空,代码如下所示:
  521.  
  522. //计时器计算属性
  523. var timer:NSTimer?
  524. var isCounting:Bool = false {
  525. //添加属性监视器,当计时开始创建timer否则停止
  526. willSet {
  527. if newValue {
  528. timer = NSTimer.scheduledTimerWithTimeInterval(, target: self, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)
  529. }else {
  530. timer?.invalidate()
  531. timer = nil
  532. }
  533. setSettingButtonsEnabled(!newValue)
  534. }
  535. }
  536. //计时方法每一秒调用改变timeLable的显示,直到计时结束
  537. func updateTimer(timer:NSTimer){
  538. remainingSeconds--
  539. if remainingSeconds<= {
  540. isCounting = false
  541. var alertVC = UIAlertController(title: "时间到", message: "", preferredStyle:.Alert)
  542. let action = UIAlertAction(title: "确定", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
  543. println("被按了")
  544. })
  545. alertVC.addAction(action)
  546. self.presentViewController(alertVC, animated: true, completion: nil)
  547. }
  548. }
  549. //打开或关闭设置时间的按钮
  550. func setSettingButtonsEnabled(enable:Bool) {
  551. for button in timeButtons {
  552. button.enabled = enable
  553. button.alpha = enable ?1.0 : 0.3
  554. }
  555. resetButton.enabled = enable
  556. resetButton.alpha = enable ?1.0 : 0.3
  557. let title = enable ? "启动" : "停止"
  558. startButton.setTitle(title, forState: .Normal)
  559. }
  560. 此时再实现startButtonTapped:和resetButtonTapped:方法,代码如下所示:
  561.  
  562. func startButtonTapped(button:UIButton){
  563. isCounting = !isCounting
  564. }
  565. func resetButtonTapped(){
  566. remainingSeconds =
  567. }
  568. 步骤四:后台计时,推送消息
  569.  
  570. IOS8对程序的后台运行有很好的支持,当计时器退到后台,不用做任何操作就会自动后台计时,但是当计时完成用户并不知道计时已经完成,所以这个时候就需要使用IOS系统提供的本地消息推送功能,首先需要在程序加载成功的方法中请求用户同意接受消息推送,代码如下所示:
  571.  
  572. func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  573. // Override point for customization after application launch.
  574. self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
  575. //可选链,设置背景颜色
  576. self.window?.backgroundColor = UIColor.whiteColor()
  577. self.window?.rootViewController = ViewController()
  578. self.window?.makeKeyAndVisible()
  579. //请求用户获取消息推送权限
  580. let settings = UIUserNotificationSettings(forTypes: UIUserNotificationType.Alert | UIUserNotificationType.Sound | UIUserNotificationType.Badge,categories: nil)
  581. application.registerUserNotificationSettings(settings)
  582. return true
  583. }
  584. 其次从计时开始就添加消息推送,当计时完成时推送消息,代码如下所示:
  585.  
  586. func startButtonTapped(button:UIButton){
  587. isCounting = !isCounting
  588. if isCounting {
  589. //添加消息推送
  590. createAndFireLocalNotificationAfterSeconds(Double(remainingSeconds))
  591. }else {
  592. //计时结束退出消息推送
  593. UIApplication.sharedApplication().cancelAllLocalNotifications()
  594. }
  595. }
  596. //添加消息推送方法
  597. func createAndFireLocalNotificationAfterSeconds(seconds:NSTimeInterval) {
  598. UIApplication.sharedApplication().cancelAllLocalNotifications()
  599. let notification = UILocalNotification()
  600. //推送时间
  601. notification.fireDate = NSDate(timeIntervalSinceNow: seconds)
  602. //推送时区
  603. notification.timeZone = NSTimeZone.systemTimeZone()
  604. //推送通知的内容
  605. notification.alertBody = "Time is up!"
  606. UIApplication.sharedApplication().scheduleLocalNotification(notification)
  607. }
  608. 运行程序消息推送效果如图-10所示:
  609.  
  610. 图-
  611.  
  612. 3.4 完整代码
  613.  
  614. 本案例中,AppDelegate.swift文件中完整代码如下所示:
  615.  
  616. import UIKit
  617. @UIApplicationMain
  618. class AppDelegate: UIResponder, UIApplicationDelegate {
  619. var window: UIWindow?
  620. func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  621. // Override point for customization after application launch.
  622. self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
  623. //可选链,设置背景颜色
  624. self.window?.backgroundColor = UIColor.whiteColor()
  625. self.window?.rootViewController = ViewController()
  626. self.window?.makeKeyAndVisible()
  627. //请求用户获取消息推送权限
  628. let settings = UIUserNotificationSettings(forTypes: UIUserNotificationType.Alert | UIUserNotificationType.Sound | UIUserNotificationType.Badge,categories: nil)
  629. application.registerUserNotificationSettings(settings)
  630. return true
  631. }
  632. }
  633.  
  634. 本案例中,ViewController.swift文件中完整代码如下所示:
  635.  
  636. import UIKit
  637. class ViewController: UIViewController {
  638. var timeLabel:UILabel!
  639. var timeButtons:[UIButton]!
  640. var startButton:UIButton!
  641. var resetButton:UIButton!
  642. //计算剩余时间
  643. var remainingSeconds:Int = {
  644. //属性监视器
  645. willSet {
  646. let min = newValue/
  647. let sec = newValue%
  648. timeLabel.text = String(NSString(format: "%02d:%02d", min,sec))
  649. }
  650. }
  651. //计时器计算属性
  652. var timer:NSTimer?
  653. var isCounting:Bool = false {
  654. //添加属性监视器,当计时开始创建timer否则停止
  655. willSet {
  656. if newValue {
  657. timer = NSTimer.scheduledTimerWithTimeInterval(, target: self, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)
  658. }else {
  659. timer?.invalidate()
  660. timer = nil
  661. }
  662. setSettingButtonsEnabled(!newValue)
  663. }
  664. }
  665. //计时方法每一秒调用改变timeLable的显示,直到计时结束
  666. func updateTimer(timer:NSTimer){
  667. remainingSeconds--
  668. if remainingSeconds<= {
  669. isCounting = false
  670. var alertVC = UIAlertController(title: "time is up", message: "", preferredStyle:.Alert)
  671. let action = UIAlertAction(title: "Done", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
  672. println("被按了")
  673. })
  674. alertVC.addAction(action)
  675. self.presentViewController(alertVC, animated: true, completion: nil)
  676. }
  677. }
  678. //打开或关闭设置时间的按钮
  679. func setSettingButtonsEnabled(enable:Bool) {
  680. for button in timeButtons {
  681. button.enabled = enable
  682. button.alpha = enable ?1.0 : 0.3
  683. }
  684. resetButton.enabled = enable
  685. resetButton.alpha = enable ?1.0 : 0.3
  686. let title = enable ? "Start" : "Stop"
  687. startButton.setTitle(title, forState: .Normal)
  688. }
  689. func setupTimeLabel(){
  690. timeLabel = UILabel()
  691. timeLabel.textColor = UIColor.whiteColor()
  692. timeLabel.font = UIFont.boldSystemFontOfSize()
  693. timeLabel.backgroundColor = UIColor.blackColor()
  694. timeLabel.textAlignment = NSTextAlignment.Center
  695. view.addSubview(timeLabel)
  696. }
  697. //预设时间按钮的信息
  698. let timeButtonsInfo = [("1min",),("3min",),("5min",),("sec",)]
  699. func setupTimeButtons(){
  700. timeButtons = []
  701. for (title,sec) in timeButtonsInfo {
  702. let button = UIButton()
  703. button.backgroundColor = UIColor.orangeColor()
  704. button.setTitle(title, forState:UIControlState.Normal)
  705. button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
  706. button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Highlighted)
  707. //记录对应的时间给tag
  708. button.tag = sec
  709. //给按钮添加点击事件
  710. button.addTarget(self, action: Selector("timeButtonTapped:"), forControlEvents: UIControlEvents.TouchUpInside)
  711. view.addSubview(button)
  712. timeButtons.append(button)
  713. }
  714. }
  715. func timeButtonTapped (button:UIButton){
  716. remainingSeconds += button.tag
  717. }
  718. //设置启动,复位按钮
  719. func setupActionButtons() {
  720. startButton = UIButton()
  721. startButton.backgroundColor = UIColor.redColor()
  722. startButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
  723. startButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
  724. startButton.setTitle("Start", forState: .Normal)
  725. view.addSubview(startButton)
  726. //添加事件
  727. startButton.addTarget(self, action: "startButtonTapped:", forControlEvents: .TouchUpInside)
  728. resetButton = UIButton()
  729. resetButton.backgroundColor = UIColor.redColor()
  730. resetButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
  731. resetButton.setTitleColor(UIColor.blackColor(), forState: .Highlighted)
  732. resetButton.setTitle("Reset", forState: .Normal)
  733. view.addSubview(resetButton)
  734. resetButton.addTarget(self, action: "resetButtonTapped:", forControlEvents: .TouchUpInside)
  735. }
  736. func startButtonTapped(button:UIButton){
  737. isCounting = !isCounting
  738. if isCounting {
  739. //添加消息推送
  740. createAndFireLocalNotificationAfterSeconds(Double(remainingSeconds))
  741. }else {
  742. //计时结束退出消息推送
  743. UIApplication.sharedApplication().cancelAllLocalNotifications()
  744. }
  745. }
  746. func resetButtonTapped(button:UIButton){
  747. remainingSeconds =
  748. }
  749. //添加消息推送方法
  750. func createAndFireLocalNotificationAfterSeconds(seconds:NSTimeInterval) {
  751. //取消之前所有的消息推送
  752. UIApplication.sharedApplication().cancelAllLocalNotifications()
  753. let notification = UILocalNotification()
  754. //推送时间
  755. notification.fireDate = NSDate(timeIntervalSinceNow: seconds)
  756. //推送时区
  757. notification.timeZone = NSTimeZone.systemTimeZone()
  758. //推送通知的内容
  759. notification.alertBody = "Time is up!"
  760. UIApplication.sharedApplication().scheduleLocalNotification(notification)
  761. }
  762. override func viewDidLoad() {
  763. super.viewDidLoad()
  764. setupTimeLabel()
  765. setupTimeButtons()
  766. setupActionButtons()
  767. }
  768. //布局代码
  769. override func viewDidLayoutSubviews() {
  770. //时间窗口的布局
  771. timeLabel.frame = CGRect(x: , y: , width: view.bounds.size.width-, height: )
  772. //时间按钮的布局:按钮大小:64x44,按钮之间的间隔
  773. let cnt = timeButtons.count -
  774. let width = view.bounds.width - *2.0 - CGFloat(timeButtons.count) * 64.0
  775. let gap = width / CGFloat(cnt)
  776. for (index, button) in enumerate(timeButtons) {
  777. let buttonLeft = 10.0 + CGFloat(index) * (64.0 + gap)
  778. button.frame = CGRectMake(CGFloat(buttonLeft), view.bounds.height-120.0, , )
  779. }
  780. //启动复位按钮的布局
  781. startButton.frame = CGRectMake(, view.bounds.height - , view.bounds.width - - , )
  782. resetButton.frame = CGRectMake( + startButton.frame.width+, view.bounds.height - , , )
  783. }
  784. }

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

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

    可选链(Optional Chaining) 可选链是一种请求或调用属性.方法,子脚本的过程. 可选性体现于请求或调用的目标当前可能为nil.若不为nil则成功调用.否则返回nil并将链失效. 调用可 ...

  2. swift学习笔记之-协议

    //协议(Protocols) import UIKit /*协议(Protocols) 1.协议定义了一个蓝图,规定了用来实现某一特定任务或者功能的方法.属性,以及其他需要的东西 2.类.结构体或枚 ...

  3. swift 学习- 23 -- 扩展

    // 扩展 就是为一个已有的 类, 结构体, 枚举, 或者 协议类型添加新功能, 这包括在没有权限获取 原始代码的情况下 扩展类型的能力 (即 逆向建模), 扩展和 OC 中的分类类似, (与 OC ...

  4. swift开发之--Protocol(协议)

    使用object-c语言的同学们肯定对协议都不陌生,但在swift中苹果将protocol这种语法发扬的更加深入和彻底. Swift中的protocol不仅能定义方法还能定义属性,配合extensio ...

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

    在Swift中协议不仅可以定义方法和属性,而且协议是可以扩展的,最关键的是,在协议的扩展中可以添加一些方法的默认实现,就是在协议的方法中可以实现一些逻辑,由于这个特性,Swift是可以面向协议进行编程 ...

  6. Swift - 类型转换(as as! as?)

    swift 类型转换 一,as 1,as使用场合 (1)从派生类转换为基类,向上转型(upcasts) class Animal {} class Cat: Animal {} let cat = C ...

  7. OAuth 2.0 扩展协议之 PKCE

    前言 阅读本文前需要了解 OAuth 2.0 授权协议的相关内容, 可以参考我的上一篇文章 OAuth 2.0 的探险之旅. PKCE 全称是 Proof Key for Code Exchange, ...

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

    Protocols and Extensions 协议(接口)和扩展 Swift使用关键字protocol声明一个协议(接口): 类(classes),枚举(enumerations)和结构(stru ...

  9. Swift 4.0:访问级别(访问控制)

    基础篇 注: 下文中所提及的类和类型为Class, Enum和Struct Swift中的访问级别有以下五种: open: 公开权限, 最高的权限, 可以被其他模块访问, 继承及复写. public: ...

  10. swift:类型转换(is用作判断检测、as用作类型向下转换)

    类型转换是一种检查类实例的方式,并且哦或者也是让实例作为它的父类或者子类的一种方式.   类型转换在Swift中使用is 和 as操作符实现.这两个操作符提供了一种简单达意的方式去检查值的类型或者转换 ...

随机推荐

  1. 多项目开发下的dll文件管理

    阅读目录: DS01:为什么要对生成的dll文件进行管理? DS02:首先介绍以下两个DOS命令 DS03:第一种实现方法(xcopy) DS04:第二种实现方法(attrib) DS05:分享一个有 ...

  2. Scala HandBook

    目录[-] 1.   Scala有多cool 1.1.     速度! 1.2.     易用的数据结构 1.3.     OOP+FP 1.4.     动态+静态 1.5.     DSL 1.6 ...

  3. redhat openshift 跳转

    网址: https://openshift.redhat.com/ OpenShift免费套餐的限制是:最多15PV/s,有3个512MB内存的应用,月流量在50K以下. 可以绑米,可惜的是,需要代理 ...

  4. [深度优先搜索] POJ 1426 Find The Multiple

    Find The Multiple Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 28550   Accepted: 118 ...

  5. Git 配置

    在 windows 上安装完 Git 会右键菜单中看到 Git 的快捷打开选项, 点 Git Bash Here 就可以在当前目录下打开 Git 的命令行 Git shell,初次使用 Git 先配置 ...

  6. window 链接方式

    一.硬链接 mklink /H <destination> <source> 创建后的图标也和原文件的图标一样,在属性中也无法看出其中的链接关系 可通过命令查看 fsutil ...

  7. 在centos环境安装mysql

    在Linux上安装mysql数据库,我们可以去其官网上下载mysql数据库的rpm包,http://dev.mysql.com/downloads/mysql/5.6.html#downloads,大 ...

  8. Text Justification

    在一段时间没刷题之后,我发现脑子严重地滞涩了.这题AC花了好大力气,出现了Memory Limit Exceed,Core Dump,以及各种普通的编译.运行错误.MLE 和 CD错误是比较难检查的, ...

  9. linux命令每日一练习 创建新文件 列出文件的时候带着行号

    touch ××× nl ****

  10. Matlab中的mapminmax函数学习

    premnmx() is obselete. Use MAPMINMAX instead. >> x1=[1 2 4] >> [y,ps]=mapminmax(x1); 得到: ...