欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Swift学习笔记七:实用进阶(一)

程序员文章站 2022-04-11 16:11:03
...

八、实用进阶

1.Swift语言中的两种单利模式

//单例模式可以保证一个类仅有一个实例。

import UIKit


//final修饰符:可以防止类被继承,还可以防止子类重写父类的属性、方法以及下标。该修饰符不能修饰结构体和枚举。

final class SingleClass: NSObject

{

    //使用static修饰符,定义一个静态常量。静态常量在实例调用结束后不会消失,并且保留原值,即其内存不会被释放。当下次调用实例时,仍然使用常量原有的值。

    static let shared = SingleClass()

    //为了保持一个单例的唯一性,单例的构造器必须是private的。以防止其他对象也能创建出单例类的实例

    private override init() {}

    

    func say()

    {

        print("Hello, CoolKeTang!")

    }

}

SingleClass.shared.say()



final class SecondSingletonClass: NSObject

{

    //使用static修饰符,定义一个静态变量。

    static var shared: SecondSingletonClass

    {

        //借助结构体来存储类型变量(class var),并使用let修饰符来保证线程的安全

        struct Static

        {

            static let instance: SecondSingletonClass = SecondSingletonClass()

        }

        return Static.instance

    }

    //为了保持一个单例的唯一性,单例的构造器必须是私有的,以防止其它对象也能创建出单例类的实例

    private override init() {}

    

    func say()

    {

        print("Hello, CoolKeTang!")

    }

}


SecondSingletonClass.shared.say()

2.Swift语言中的三种消息传递模式

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let width = Int(self.view.frame.size.width - 40)
        let greetingButton = UIButton(frame: CGRect(x: 20, y: 100, width: width, height: 40))
        greetingButton.setTitle("Greeting", for: .normal)
        greetingButton.backgroundColor = .orange
        //绑定按钮点击事件
        greetingButton.addTarget(self, action: #selector(ViewController.buttonTapped), for: .touchUpInside)
        //如果方法位于当前的类中,可以省略方法名称前方的类名
        greetingButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        greetingButton.tag = 1
        //(_:)->小括号表示该方法拥有参数,下划线表示隐藏外部参数名
        greetingButton.addTarget(self, action: #selector(buttonTappedFor(_:)), for: .touchUpInside)
        //初始化一个选择器对象,并设置它的方法名称
        let anotherMethod : Selector = #selector(buttonTappedFor(_:))
        greetingButton.addTarget(self, action: anotherMethod, for: .touchUpInside)
        
        //添加按钮
        self.view.addSubview(greetingButton)
        
        //创建选择器
        let timerSelector = #selector(ViewController.timerAction(_:))
        //创建定时器
        Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: timerSelector, userInfo: "parameter", repeats: true)
        
        let newSelector = #selector(calledByController)
        //通过视图控制器对象的perform方法,在子线程中调用该选择器
        self.perform(newSelector)
        //延迟2秒
        self.perform(newSelector, with: nil, afterDelay: 2.0)
        //在主线程中调用选择器,并等待动作的执行。当对界面元素进行操作时,需要在主线程中进行
        self.perform(newSelector, on: .main, with: nil, waitUntilDone: true)
        //在后台线程中运行整个方法
        self.performSelector(inBackground: newSelector, with: nil)
    }
    
    @objc func buttonTapped()
    {
        print("buttonTapped")
    }
    
    @objc func buttonTappedFor(_ sender: UIButton)
    {
        let tag = sender.tag
        print("button tag: \(tag)")
    }
    
    @objc func timerAction(_ timer:Timer)
    {
        let parameter = timer.userInfo
        print(parameter ?? "")
    }
    
    @objc func calledByController()
    {
        print("calledByController")
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

3.闭包在定时任务、动画和线程中的使用

import UIKit

class ViewController: UIViewController {

    //初始化一个视图
    var animationVeiw : UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        //定时器执行闭包
        Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (timer:Timer) in
            print("Timer action...")
        }

        animationVeiw = UIView(frame: CGRect(x: 0, y: 40, width: 50, height: 50))
        animationVeiw.backgroundColor = .orange
        self.view.addSubview(animationVeiw)
        
        //动画
        UIView.animate(withDuration: 1.0, animations: {
            self.animationVeiw.frame = CGRect(x: 200, y: 40, width: 50, height: 50)
        }) { (end:Bool) in
            print("Animation done.")
        }
        
        //分离一个新的线程,并在新的线程中执行闭包语句中的任务
        Thread.detachNewThread {
            print("Do something on a new thread.")
        }
        
        //在调度队列中,异步执行闭包语句中的任务
        DispatchQueue.main.async {
            print("DispatchQueue.main.async")
        }

        //2秒后,异步执行闭包语句中的任务
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0) {
            print("DispatchQueue.main.asyncAfter")
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

4.通过protocol在两个对象中进行消息传递

CustomView.swift

import UIKit

//创建协议,校验输入框中的文本内容
protocol DemoDelegate
{
    func checkForm()
}

//遵守UITextField协议
class CustomView: UIView, UITextFieldDelegate {

    var textField : UITextField!
    var delegate : DemoDelegate? //添加协议属性
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        textField = UITextField(frame:CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
        textField.font = UIFont.boldSystemFont(ofSize: 14)
        textField.textColor = .purple
        textField.layer.shadowColor = UIColor.black.cgColor
        textField.layer.shadowOffset = CGSize(width: 0.0, height: 3.0)
        textField.layer.shadowOpacity = 0.45
        textField.layer.shadowRadius = 3
        textField.backgroundColor = .lightGray
        textField.delegate = self
        
        self.addSubview(textField)
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        
        self.delegate?.checkForm()
        return true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

ViewController.swift

import UIKit

class ViewController: UIViewController, DemoDelegate {

    var nameField : CustomView!
    var passwordField : CustomView!
    var submitButton : UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let width = Int(self.view.frame.size.width) - 40
        let height = 40
        
        nameField = CustomView(frame: CGRect(x: 20, y: 80, width: width, height: height))
        nameField.delegate = self
        self.view.addSubview(nameField)
        
        passwordField = CustomView(frame: CGRect(x: 20, y: 140, width: width, height: height))
        passwordField.delegate = self
        self.view.addSubview(passwordField)
        
        submitButton = UIButton(frame: CGRect(x: 20, y: 240, width: width, height: height))
        submitButton.setTitle("Sumbit", for: .normal)
        submitButton.addTarget(self, action: #selector(ViewController.submitForm(_:)), for: .touchUpInside)
        submitButton.backgroundColor = .gray
        submitButton.isEnabled = false
        self.view.addSubview(submitButton)
    }
    
    func checkForm()
    {
        if self.nameField.textField.text != "" && self.passwordField.textField.text != ""
        {
            self.submitButton.isEnabled = true
            submitButton.backgroundColor = .orange
        }
        else
        {
            self.submitButton.isEnabled = false
            submitButton.backgroundColor = .gray
        }
    }
    
    @objc func submitForm(_ sender:UIButton)
    {
        print("submitForm....")
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

5.通过间接代理进行对象间的消息传递

CustomView.swift

import UIKit

class CustomView: UIView {

    var textField : UITextField!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        textField = UITextField(frame:CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
        textField.font = UIFont.boldSystemFont(ofSize: 14)
        textField.textColor = .purple
        textField.layer.shadowColor = UIColor.black.cgColor
        textField.layer.shadowOffset = CGSize(width: 0.0, height: 3.0)
        textField.layer.shadowOpacity = 0.45
        textField.layer.shadowRadius = 3
        textField.backgroundColor = .lightGray
        
        self.addSubview(textField)
    }
    
    func setController(controller : ViewController)
    {
        self.textField.delegate = controller
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

ViewController.swift

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    var nameField : CustomView!
    var passwordField : CustomView!
    var submitButton : UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let width = Int(self.view.frame.size.width) - 40
        let height = 40
        
        nameField = CustomView(frame: CGRect(x: 20, y: 80, width: width, height: height))
        nameField.setController(controller: self)
        self.view.addSubview(nameField)
        
        passwordField = CustomView(frame: CGRect(x: 20, y: 140, width: width, height: height))
        passwordField.setController(controller: self)
        self.view.addSubview(passwordField)
        
        submitButton = UIButton(frame: CGRect(x: 20, y: 240, width: width, height: height))
        submitButton.setTitle("Sumbit", for: .normal)
        submitButton.addTarget(self, action: #selector(ViewController.submitForm(_:)), for: .touchUpInside)
        submitButton.backgroundColor = .gray
        submitButton.isEnabled = false
        self.view.addSubview(submitButton)
    }
    
    @objc func submitForm(_ sender:UIButton)
    {
        print("submitForm....")
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool
    {
        if self.nameField.textField.text != "" && self.passwordField.textField.text != ""
        {
            self.submitButton.isEnabled = true
            submitButton.backgroundColor = .orange
        }
        else
        {
            self.submitButton.isEnabled = false
            submitButton.backgroundColor = .gray
        }
        return true
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

6.通过属性进行对象间的消息传递

CustomView.swift

import UIKit

class CustomView: UIView, UITextFieldDelegate {

    var textField : UITextField!
    weak var controller : ViewController?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        textField = UITextField(frame:CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
        textField.font = UIFont.boldSystemFont(ofSize: 14)
        textField.textColor = .purple
        textField.layer.shadowColor = UIColor.black.cgColor
        textField.layer.shadowOffset = CGSize(width: 0.0, height: 3.0)
        textField.layer.shadowOpacity = 0.45
        textField.layer.shadowRadius = 3
        textField.backgroundColor = .lightGray
        textField.delegate = self
        
        self.addSubview(textField)
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        
        self.controller?.checkForm()
        return true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

ViewController.swift

import UIKit

class ViewController: UIViewController {

    var nameField : CustomView!
    var passwordField : CustomView!
    var submitButton : UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let width = Int(self.view.frame.size.width) - 40
        let height = 40
        
        nameField = CustomView(frame: CGRect(x: 20, y: 80, width: width, height: height))
        nameField.controller = self
        self.view.addSubview(nameField)
        
        passwordField = CustomView(frame: CGRect(x: 20, y: 140, width: width, height: height))
        passwordField.controller = self
        self.view.addSubview(passwordField)
        
        submitButton = UIButton(frame: CGRect(x: 20, y: 240, width: width, height: height))
        submitButton.setTitle("Sumbit", for: .normal)
        submitButton.addTarget(self, action: #selector(ViewController.submitForm(_:)), for: .touchUpInside)
        submitButton.backgroundColor = .gray
        submitButton.isEnabled = false
        self.view.addSubview(submitButton)
    }
    
    func checkForm()
    {
        if self.nameField.textField.text != "" && self.passwordField.textField.text != ""
        {
            self.submitButton.isEnabled = true
            submitButton.backgroundColor = .orange
        }
        else
        {
            self.submitButton.isEnabled = false
            submitButton.backgroundColor = .gray
        }
    }
    
    func submitForm(_ sender:UIButton)
    {
        print("submitForm....")
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

7.使用通知的方法进行对象间的数据传递

CustomView.swift

import UIKit

class CustomView: UIView, UITextFieldDelegate {

    var textField : UITextField!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        textField = UITextField(frame:CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
        textField.font = UIFont.boldSystemFont(ofSize: 14)
        textField.textColor = .purple
        textField.layer.shadowColor = UIColor.black.cgColor
        textField.layer.shadowOffset = CGSize(width: 0.0, height: 3.0)
        textField.layer.shadowOpacity = 0.45
        textField.layer.shadowRadius = 3
        textField.backgroundColor = .lightGray
        textField.delegate = self
        
        self.addSubview(textField)
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool
    {
        //发送通知
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "checkFormNotification"),
                                        object: nil,
                                        userInfo: nil)
        return true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

}

ViewController.swift

//通知中心是一个调度消息通知的类,采用单例设计模式,实现数据传递、回调等功能。
import UIKit

class ViewController: UIViewController {

    var nameField : CustomView!
    var passwordField : CustomView!
    var submitButton : UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let width = Int(self.view.frame.size.width) - 40
        let height = 40
        
        nameField = CustomView(frame: CGRect(x: 20, y: 80, width: width, height: height))
        self.view.addSubview(nameField)
        
        passwordField = CustomView(frame: CGRect(x: 20, y: 140, width: width, height: height))
        self.view.addSubview(passwordField)
        
        submitButton = UIButton(frame: CGRect(x: 20, y: 240, width: width, height: height))
        submitButton.setTitle("Sumbit", for: .normal)
        submitButton.addTarget(self, action: #selector(ViewController.submitForm(_:)), for: .touchUpInside)
        submitButton.backgroundColor = .gray
        submitButton.isEnabled = false
        self.view.addSubview(submitButton)
        
        //接收通知
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(ViewController.checkForm(_:)),
                                               name: NSNotification.Name(rawValue: "checkFormNotification"),
                                               object: nil)
    }
    
    @objc func checkForm(_ notification: Notification?)
    {
        if self.nameField.textField.text != "" && self.passwordField.textField.text != ""
        {
            self.submitButton.isEnabled = true
            submitButton.backgroundColor = .orange
        }
        else
        {
            self.submitButton.isEnabled = false
            submitButton.backgroundColor = .gray
        }
    }
    
    @objc func submitForm(_ sender:UIButton)
    {
        print("submitForm....")
    }
    
    deinit
    {
        //销毁通知(必写)
        NotificationCenter.default.removeObserver(self)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

8.使用performSegue在故事板页面之间进行数据传递

DetailViewController.swift

import UIKit

class DetailViewController: UIViewController {

    var parameter : String!
    @IBOutlet var detailLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.detailLabel.text = self.parameter
    }

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

ViewController.swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
    }
    
    @IBAction func showDetail(_ sender: Any) {
        //点击按钮时,通过指定名称的连接线,在导航控制器中,跳转到第二个视图控制器
        self.performSegue(withIdentifier: "showDetail", sender: nil)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //重写父类方法,用来监听故事版中的连接线的跳转动作
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let vc = segue.destination as! DetailViewController
        vc.parameter = "Hello, CoolKeTang!"
    }

}
Swift学习笔记七:实用进阶(一)

9.Swift中的栈Stack和队列Queue详解

Swift语言并没有提供内设的栈和队列,很多扩展类库都是使用泛型来实现栈或队列。下面将采用数组来实现栈和队列等数据结构。

import UIKit

//栈:后进先出的线性结构
class Stack
{
    var stack: [AnyObject]
    
    //初始化
    init()
    {
        stack = [AnyObject]()
    }
    
    //非空判断
    func isEmpty() -> Bool
    {
        return stack.isEmpty
    }
    
    //大小
    func size() -> Int
    {
        return stack.count
    }
    
    //进栈
    func push(object: AnyObject)
    {
        stack.append(object)
    }
    
    //出栈
    func pop() -> AnyObject?
    {
        if isEmpty()
        {
            return nil
        }
        else
        {
            return stack.removeLast() //最后一个数组元素
        }
    }
}

var stack = Stack()
stack.isEmpty()
stack.push(object: UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0))
stack.push(object: UIColor(red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0))
stack.pop()

//队列:先进先出的线性结构
class Queue
{
    var queue: [AnyObject]
    
    //初始化
    init()
    {
        queue = [AnyObject]()
    }
    
    //非空判断
    func isEmpty() -> Bool
    {
        return queue.isEmpty
    }
    
    //大小
    func size() -> Int
    {
        return queue.count
    }
    
    //加入队列
    func joinQueue(object: AnyObject)
    {
        queue.append(object)
    }
    
    //出队列
    func deQueue() -> AnyObject?
    {
        if isEmpty()
        {
            return nil
        }
        else
        {
            return queue.removeFirst()//第一个元素
        }
    }
}

var queue = Queue()
queue.isEmpty()
queue.joinQueue(object: UIColor(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0))
queue.joinQueue(object: UIColor(red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0))
queue.deQueue()


10.Swift中的链表LinkedList详解

链表是一种物理存储单元上的非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

链表由一系列节点组成,每个节点包括两个部分,一个是存储数据元素的数据域,另一个是存储下个节点地址的指针域。

class LinkedListNode
{
    var content: Int    //链表的数据域
    var nextNode: LinkedListNode? //链表的指针域
    
    init(_ content: Int)
    {
        self.content = content
        self.nextNode = nil
    }
}

class LinkedList
{
    var head: LinkedListNode? //头节点
    var end: LinkedListNode?  //尾节点
    
    //添加到当前节点头部
    func appendToHead(content: Int)
    {
        if head == nil
        {
            head = LinkedListNode(content)
            end = head
        }
        else
        {
            let temporaryNode = LinkedListNode(content)
            temporaryNode.nextNode = head
            head = temporaryNode
        }
    }
    //添加到当前节点尾部
    func appendToEnd(content: Int)
    {
        if end == nil
        {
            end = LinkedListNode(content)
            head = end
        }
        else
        {
            end?.nextNode = LinkedListNode(content)
            end = end?.nextNode
        }
    }
}