form1.cn
Make a little progress every day

Part 7:iOS常用设计模式-单例模式-委托模式-观查者模式

08th of March 2017 Swift Swift 1811

本章中主要学习了设计模式:

1,单例模式

在一个 iOS 应用的生命周期中,有时候我们只需要某个类的一个实例。例如:当应用程序启动时,应用的状态由 UIApplication 类的一个实例维护,这个实例代表了整个应用程序对象”,它只能是一个实例,其作用是实现应用 程序中一些共享资源的访问和状态的保持等。


2,委托模式

假设这一系列的处理都是在上帝类 UIApplication 中完成的。之所以叫“上帝类(god class)”,是因为它“无所不 能”、“包含所有”。 在面向对象的软件设计中,“上帝类”不是很友好,需要重构。在编程过程中,要尽量避免使 用上帝类,因为上帝类是高耦合的,职责不清,难以维护。我们需要“去除上帝类”,把看似功能很强且很难维护 的类,按照职责将它的属性或方法分派到各自的类中或分解成功能明确的类。


3,观查者模式

通知机制与KVO机制


单例模式实现代码

import Foundation

//简单单例模式的实现方法
class Singleton{
    private static let sharedInstance = Singleton() //单例的实例保存这个属性中
    public let myint: Int = 89
    class var sharedFoo: Singleton { //swift中的静态计算属性
        return sharedInstance
    }
}

/*
 
 ******* dispatch_once_t 在swift3.0中被干掉了,所以以下代码是一堆垃圾
 
 //GCD 实现的单例设计模式
 //dispatch_once_t 类型,是一种基于 C 语言的多线程访问技术 Grand Central Dispatch(缩写,GCD),dispatch_once_t 是 GCD 提供的结构体。代码 token 地址传给 dispatch_once 函数。dispatch_once 函数能够记录该代码块是否被调 用过。dispatch_once 函数不仅意味着代码仅会被运行一次,而且还意味着此运行还是线程同步的。
 class Singleton {
 
 class var sharedInstance: Singleton {//swift中的静态计算属性, objc 的一个方法
 struct Static { //定义一个结构体
 static var instance: Singleton?//单例的实例保存这个属性中
 static var token: dispatch_once_t = 0 //GCD 并发访问相关
 }
 
 //GCD 函数 dispatch_once 1,只会运行一次 2,可以线程同步
 dispatch_once(&Static.token) {
 Static.instance = Singleton() //实例化单例类,只执行一次,把实例化的实例放入instance属性中
 }
 
 return Static.instance! //返回实例
 }
 
 }
 
 /
 
 
 class ViewController: UIViewController 另一文件中进行测试
 //测试单例模式,两次调用但只实例化了一次,所以会输出 ”相同实例“
        let s1 = Singleton.sharedFoo
        let s2 = Singleton.sharedFoo
        if (s1 === s2) {
            NSLog("相同实例")
        } else {
            NSLog("不相同实例")
        }
        //输出单例模式的属性值,也可以有方法
        print(s1.myint)


委托协议代码实现

import UIKit

//定义的Philosopher委托协议类
class Philosopher : NSObject {
    
    var timer : Timer!
    var count : Int = 0
    var delegate:PhilosopherDelegate?
    
    //start 每隔3秒调用handle方法,
    func start() {
        count = 0
        timer = Timer.scheduledTimer(timeInterval: 2.0,
                                                       target: self,
                                                       selector: #selector(Philosopher.handle),
                                                       userInfo: nil,
                                                       repeats: true)
    }
    
    //调用协议中的三个方法
    func handle() {
        
        if count == 0 {
            self.delegate?.sleep()
            count += 1
        } else if  count == 1 {
            self.delegate?.eat()
            count += 1
        }  else if  count == 2 {
            self.delegate?.work()
            timer.invalidate()
        }
    }
    
}



//自定义的Philosopher协议委托
protocol PhilosopherDelegate {
    
    func sleep()
    
    func eat()
    
    func work()
    
}



import UIKit

//委托模式,PhilosopherDelegate为自定义的协议委托,里面有三个方法
class DelegateViewController: UIViewController,PhilosopherDelegate {

    @IBOutlet weak var oneLabel: UILabel!
    @IBOutlet weak var twoLabel: UILabel!
    @IBOutlet weak var threeLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //实例化Philosopher这个例
        let tom = Philosopher()
        //将Philosopher的委托指向当前视图
        tom.delegate = self
        //调用Philosopher的start方法,运行PhilosopherDelegate的委托方法
        tom.start()
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    //实现PhilosopherDelegate委托方法
    //将睡觉,吃饭,工作的事情委托给PhilosopherDelegate去做
    func sleep() {
        self.oneLabel.text = "Sleep"
        NSLog("sleep...")
    }
    
    func eat() {
        self.twoLabel.text = "Eat"
        NSLog("eat...")
    }
    
    func work() {
        self.threeLabel.text = "Work"
        NSLog("work...")
    }
        
}


观看者模式-通知机制

import UIKit

//通知模式,接收通知  观查者,观查对象之间的变化
class NoticeViewController: UIViewController {

    @IBOutlet weak var saveTextfield: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //(接收通知)监听通知事件RegisterCompletionNotification,交给registerCompletion函数处理
        NotificationCenter.default.addObserver(self, selector: #selector(registerCompletion(notification:)), name: NSNotification.Name.init(rawValue: "RegisterCompletionNotification"), object: nil)// . object: nil 可以发送通知的视图接收过来
        
        //selector无参数设置方法 @ selector: #selector(addPhoto)
        //selector有参数设置方法 @ selector: #selector(addPhoto(noti:))
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        //注销当前视图所有通知
        NotificationCenter.default.removeObserver(self)
    }
    
    //实现通知监听方法
    func registerCompletion(notification : NSNotification) {
        //把通知投送的字典信息取出,放入一个字典类型
        let userInfo:Dictionary<String,String?> = notification.userInfo as! Dictionary<String,String?>
        //取投送时定义的forkey对应的字典值
        let username = userInfo["username"]!
        //将值显示到textField中
        self.saveTextfield.text = username
    }
    

}


import UIKit

//通知模式,发送通知 (观查者,观查对象之间的变化)
class NoticeMTViewController: UIViewController {

    @IBOutlet weak var myTextfield: UITextField!
    
    @IBAction func onCencel(_ sender: UIBarButtonItem) {
        //关闭模态
        self.dismiss(animated: true, completion: {() -> Void in
            print("关闭模态")
        })
    }
    
    @IBAction func onSeve(_ sender: UIBarButtonItem) {
        //关闭模态
        self.dismiss(animated: true, completion: {() -> Void in
            print("关闭模态")
            
            //注册通知,传输数据 . object: nil 可以把当前视图发送过去
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "RegisterCompletionNotification"), object: nil, userInfo: ["username" : self.myTextfield.text as Any])
            
        })
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
}


观查者模式-KVO机制

import UIKit

//KVO通知机制,观查对象属性的变化,继承NSObject重写observeValue方法
class AppStatusObserver: NSObject {
    
    //最终运行的方法,@keyPath观查的属性名子,@object被观看的对象,@change通地属性可以得到属性的new与old的val
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        print("AppStatusObserver: \(keyPath! as String) - \(change?[NSKeyValueChangeKey.newKey]! as! String)")
        
    }
}



import UIKit

@UIApplicationMain

//例用APP的前后台切换改变appStatus的值 来测试 KVO观查者机制
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    
    //被观查的属性,@ 必须是动态的,要添加关键字:dynamic
    dynamic var appStatus: NSString!
    var observer: AppStatusObserver!


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        //实例化观查者类:AppStatusObserver
        self.observer = AppStatusObserver()
        //为属性变化对象添加观查者对象,@观查者对象,@观看的属性名称,@观看appStatus的新值或老值,@上下文对像nil
        self.addObserver(self.observer, forKeyPath: "appStatus", options: NSKeyValueObservingOptions.new, context: nil)
        //改变被观查属性的值
        self.appStatus = "launch"
        
        
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        self.appStatus = "inactive"
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        self.appStatus = "background"
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        self.appStatus = "inactive"
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        self.appStatus = "active"
    }

    func applicationWillTerminate(_ application: UIApplication) {
        self.appStatus = "terminate"
    }


}


ViewController,单例和KVO的实现与调用

import UIKit

//单例设计模式,永远只实例一个实例,被共享使用 可减少内存开销
class ViewController: UIViewController {

    
    @IBAction func openUrl(_ sender: UIButton) {
        // 单例设计模式:打开URL
        let url = URL(string: "http://form1.cn")
        //打开一个URL到浏览器中
        UIApplication.shared.open(url!, options: [:], completionHandler: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //属性变化对象是AppDelegate,所以要获得AppDelegate对像
        let appdelegate:AppDelegate = UIApplication.shared.delegate as! AppDelegate
        //为属性变化对象添加观查者对象,@观查者对象为当前对像,@观看的属性名称,@观看appStatus的新值或老值,@上下文对像nil
        appdelegate.addObserver(self, forKeyPath: "appStatus", options: NSKeyValueObservingOptions.new, context: nil)
        
        
        //测试单例模式,两次调用但只实例化了一次,所以会输出 ”相同实例“
        let s1 = Singleton.sharedFoo
        let s2 = Singleton.sharedFoo
        if (s1 === s2) {
            NSLog("相同实例")
        } else {
            NSLog("不相同实例")
        }
        //输出单例模式的属性值,也可以有方法
        print(s1.myint)
        
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //KVO通知机制,观查对象属性的变化, 重写observeValue方法
    //最终运行的方法,@keyPath观查的属性名子,@object被观看的对象,@change通地属性可以得到属性的new与old的val
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        print("UIViewController: \(keyPath! as String) - \(change?[NSKeyValueChangeKey.newKey]! as! String)")
        
    }

}