• UINavigatioUInController的基本用法和页面传值几种方式本文介绍UINavigationController基本用法,因为涉及多页面顺便介绍页面传值1、手写代码创建UINavigationController手写方式...然后在AppDelegate.swift 的didFini

    UINavigationController的基本用法和页面传值几种方式

    本文介绍UINavigationController基本用法,因为涉及多页面顺便介绍页面传值


    1、手写代码创建UINavigationController

    手写方式创建很简单 , 首先创建一个项目 , 默认是从storyboard 加载的。这时候首先去掉默认加载方式 。
    这里写图片描述

    然后在AppDelegate.swiftdidFinishLaunchingWithOptions 中创建
    代码如下:

    
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            // Override point for customization after application launch.
    
            //在这里用代码来创建NavigationController
            window = UIWindow(frame: UIScreen.mainScreen().bounds)
            window?.makeKeyAndVisible()
    
            UINavigationBar.appearance().tintColor = UIColor.whiteColor()
            UINavigationBar.appearance().barTintColor = UIColor(red: 231.0/255.0, green: 95.0/255.0, blue: 53.0/255.0, alpha: 0.3) //修改导航栏背景色
            UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()] //为导航栏设置字体颜色等
            let rootCv = ViewController();
            let nav = UINavigationController(rootViewController: rootCv)
            window?.rootViewController = nav
    
            return true
        }
    

    不要一看这么多代码,其实没这么多 。UINavigationBar 开头的都是为这个导航栏设置的样式。完全可以不要用默认的,主要就5行 ,前两行创建window 并让window显示 , 后三行创建导航控制器 , 并设置跟控制器 ,然后把window的根控制器设置成这个导航控制器 。这样就OK了。

    运行后发现有黑框 ,暴力解决 ,设置下背景色就行了 。然后再添加个 BarButtonItem 什么的

      self.view.backgroundColor = UIColor.whiteColor()
            self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Next", style: .Plain, target: self, action: "goNext:")
            self.title = "导航标题"  //设置导航栏title(不是  self.navigationController?.title 哦!)
            self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "我把返回修改了", style: .Plain, target: nil, action: nil)

    这里最后一句是修改了返回的BarButtonItem 文字 , 这里设置了标题,又加了个rightBarButtonItem 注册了事件goNext 我们来实现下。

    func goNext(sender:AnyObject){
            print("去下一个咯")
            let mainVc = UIStoryboard(name: "Third", bundle: nil).instantiateViewControllerWithIdentifier("three") as UIViewController
            self.navigationController?.pushViewController(mainVc, animated: true)
        }

    一看这个又晕了 ,中间那些是什么呀 。。首先我们从storyboard创建了一个控制器(手写的看过了,为了多学点知识) ,这里的instantiateViewControllerWithIdentifier 中的three 如下设置
    这里写图片描述

    然后push进去 。 导航控制器是采用栈的方式先进后出 , 用push和pop 。那个storyboard 中很简单就放了一个Label 和一个Button ,等会再介绍那个 ,先看看效果

    这里写图片描述

    然后我们给那个按钮也注册个事件 ,这里直接拖就行了。
    实现如下

     @IBAction func showTabBar(sender: AnyObject) {
            let mainVc = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("second") as! UINavigationController
            self.presentViewController(mainVc, animated: true) { () -> Void in
    
            }
        }

    这里还是从storyboard 中加载控制器 , 但是却用了presentViewController ,因为导航控制器不让push导航控制器 ,这边主要是像演示通过storyboard 创建导航控制器

    2、 通过storyboard 创建UINavigationController

    如果你跟我一样用Main.storyboard , 可以先删除默认的那个控制器 , 从右边拖出来一个UINavigationController ,这个会默认带一个UITableViewController , 删掉,拖一个普通的UIViewController 。选中UINavigationController 右键拖到那个UIViewController 选择rootViewController就行了 。然后可以自己拖BarButtonItem 也可以在代码中写 。我这边是拖进来的
    这里写图片描述

    就是这么拖的 , 因为我这边拖过了就不再拖了,注册事件也是拖,跟button一样的。就不再演示 。

    这时候运行效果。
    这里写图片描述

    这里是用presentViewController 弹出的返回用dismissViewControllerAnimated

     @IBAction func goBack(sender: UIBarButtonItem) {
            self.dismissViewControllerAnimated(true) { () -> Void in
                print("返回")
            }
        }

    导航控制器基本操作很简单 ,下面看下载不同页面中正反传值

    3、页面传值的几种方式

    • 正面反面传值 (协议)

    大家看到那个页面我们放了三个按钮和一个输入框 ,按钮都注册了事件。然后手写了一个新的控制器 ,里面是一个返回按钮和几个label 还有一个输入框 。

    当我们点击第一个按钮的时候进入下一个控制器 , push进去的 ,那个控制器有个方法 。

    func  passParams(tmpStr: String){
            lb.text = tmpStr
        }

    所以我们在push前,调用这个方法正面传值, 当然你可以直接给他的共有属性赋值。

    let vc = ViewControllerFour()
    let value = tf1.text
    vc.passParams(value!)
            self.navigationController?.pushViewController(vc, animated: true)

    很简单, lb.text = tmpStr 会把传过来的值赋值给label

    反向传值这里使用了代理,先声明一个协议

    protocol ParameterDelegate{
        func passParams(tmpStr: String)
    }

    然后在我们第一个页面实现这个协议 。实现对应的方法

        func passParams(tmpStr: String){
            tf1.text = tmpStr
        }

    然后在第二页面声明代理为自己的变量

     var delegate:ParameterDelegate?

    在push之前把自己设置为第二个页面的代理

      let vc = ViewControllerFour()
     vc.delegate = self  //通过代理进行反向传值
     let value = tf1.text
     vc.passParams(value!)
            self.navigationController?.pushViewController(vc, animated: true)

    注意到没,比刚才多一句话

    OK ,这样就搞定了。来看效果 !
    这里写图片描述

    • 第二种方法 (通过segue进行的传值)

    直接通过storyboard拖拽, 话说storyboard做界面还真方便 , 需要好好研究一下

    重新拖一个控制器然后连线,我这边已经拖好了,我就演示下连线

    这里写图片描述
    然后在代码中

      //通过segue进行的传值
        override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
            if segue.identifier == "toshow" {
                let vc = segue.destinationViewController as! ViewControllerTwoShow
                vc.tmpStr = tf1.text
                //vc.setValue(tf1, forKey: "tmpStr")
            }
        }

    在目标控制器中定义了变量tmpStr (后面会把代码分享出来)

    看下效果
    这里写图片描述

    • 通过通知的方式
        let vc = ViewControllerFour()
            vc.delegate = self  //通过代理进行反向传值
    
            self.presentViewController(vc, animated: true) { () -> Void in
    //发布一条通知NSNotificationCenter.defaultCenter().postNotificationName("DefaultNotif", object:self.tf1.text)
            }

    先注册一个通知 , 展现界面完成的时候发布一个通知 。在另一个界面的viewWillAppear接收通知 。

     override func viewWillAppear(animated: Bool) {
            //self.navigationController?.hidesBarsOnSwipe = true
            self.navigationController?.setNavigationBarHidden(true, animated: true) //隐藏导航栏
    
            NSNotificationCenter.defaultCenter().addObserver(self, selector: "doSomeT:", name: "DefaultNotif", object: nil)
        }

    对应方法

    func doSomeT(title:NSNotification){
            lb1.text = title.object as? String
        }

    看看效果 :
    这里写图片描述

    大概就这么多吧 , 最后把源码发上来吧, 语文不太好估计没讲清楚,大家可以看源码。以后源码都放这个地址了(觉得还行的话给个star 哦)
    githubSwiftStudy

    展开全文
  • swift3.0 基础知识点

    2016-11-21 19:29:23
    // ViewController.swift // swift_01 // // Created by weiphone on 16/8/26. // Copyright © 2016年 weiphone. All rights reserved. // import UIKit class ViewContr

    //

    //  ViewController.swift

    //  swift_01

    //

    //  Created by weiphone on 16/8/26.

    //  Copyright © 2016 weiphone. All rights reserved.

    //


    import UIKit


    class ViewController: UITabBarController {


        enum DayssofaWeek { // 星期

            case Sunday

            case Monday

            case TUESDAY

            case WEDNESDAY

            case Thursday

            case Friday

            case Saturday

        }

        

        enum Student { // 学生

            case Name(String)

            case Mark(Int, Int, Int)

            

            func studentSSS(a:Int, b:Int) -> Int {

                

                return a+b

            }

        }

        

        

        struct MarkStruct { //结构体

            var English: Int

            var Chines: Int

            var Math: Int

            

            func markStrDid(English:Int, Math:Int) -> Int {

                return English+Math

            }

            

            // (1) mutating 可以从方法内部改变它的属性;并且它做的任何改变在方法结束时还会保留在原始结构中

            mutating func subMarks(english:Int, math:Int) -> Int//

                self.English += english  //在可变方法中给self赋值 : 可变方法能够赋给隐含属性 self 一个全新的实例。

                Math += math // 改变它的属性,并且它做的任何改变在方法结束时还会保留在原始结构中

                

                print("英语 ", self.English, self.Math)

                

                return self.English-self.Math

            }

            

            // (2) 方法的func关键字之前加上关键字static。类可能会用关键字class来允许子类重写父类的实现方法

            static func minMarks(english:Int, math:Int) -> Int {

                

                if english < math {

                    return english

                } else {

                    return math

                }

                

            }

            

            // (3)下标脚本 :  subscript

            subscript(index:Int) -> Int {

                return English / index

            }

            

            // (4)下标脚本的重载

            subscript(row:Int, columns:Int) -> Int {

                get {

                    return (row * columns) + columns

                }

                set {

                    

                }

                

            }

        }


        

        

        

        override func viewDidLoad() {

            super.viewDidLoad()

            // Do any additional setup after loading the view, typically from a nib.

            

            self.view.backgroundColor = UIColor.grayColor()

            

            

            

    //        let nav1 = UINavigationController.init(rootViewController: FirstViewController)

    //        let nav2 = UINavigationController.init(rootViewController: FirstViewController)

    //        

    //        self.viewControllers:[nav1, nav2]


            

            

            


            

            //<!----------- 0.基本语法 ---------------->

            // (1)swift引入

            // import语句引入OC框架(或C库)到swift程序中,

            // swift应用中可以简单额的混入CC++语言代码,

            

            // (2)swift标记 : swift程序由多种标记组成, 标记可以是单词、标识符、常量、字符串或符号,

            print("test!") // 标记是:单词、符号

            

            // (3)注释

            // C语言注释极其相似,  不同之处是多行注释可以嵌套在其他的多行注释的内部

            // 单行注释:  //     多行注释:  /* */

            /*

             /*  嵌套注释  */

             */

            

            // (4)分号 : 不要求每行语句的结尾处使用分号(;) 但是在同一行书写多条语句时要用分号隔开

            print("分号;;;;")

            let _fenhao:NSString = "分号"; print(_fenhao)


            // (5)标识符 

            // 标识符就是给常量、变量、方法、函数、枚举、结构体、类、协议、等指定的名字

            // 命名规则: 可由下划线、数字、字母组成, 不可以数字开头, 区分大小写若非要以关键字作为标识符需要在关键字前后添加重音符号(')

            

            

            // (6)关键字

            /*    关键字类似于标识符的保留字符序列,除非用重音符号(')将其括起来, 不然不可作为标识符。 关键字是对编译器具有特殊意义的预定义保留标识符。

                {

                    与声明有关的关键字 : calss func let public typealias deinit import operator static var enum init private struct

                                      extension internal protocol subscript

                    与语句有关的关键字 : if else   for in break continue  return   do while switch case where  default  fallthrough

                    表达式和类型关键字 : is true fale nil as  self super dynamic _COLUMN_  _LINE_  _FILE_  _FUNCTION_

                    在特定上下文中使用的关键字 :

                                             associativity convenience dynamic didSet

                                             final get infix inout

                                             lazy left mutating none

                                             nonmutating optional override postfix

                                             precedence prefix Protocol required

                                             right set Type unowned

                                             weak willSet

             

                }

             */

            

            

            // (7)swift空格 : swift中,运算符不能直接跟在变量或常量的后面

            // 错误例 let aaa= "12344"     let aaa = 1 + 2(1 + 语句到此结束, 2是下一个语句)

            let aaa = 1 + 2; // 规范编码推荐使用

            let bbb = 2+3    // ok

            print(aaa,bbb)

            


            // (8)swift字面量 : 指特定的数字、字符串或布尔值这样,能够直接了当的指出自己的类型并为变量进行赋值

            42  // 整形字面量

            3.14159  // 浮点型字面量

            "hellow swift!"  //字符串字面量

            true    // 布尔值字面量

            

            

            

    //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 1.常量 ---------------->

            // (1)常量声明 (使用关键字let声明)

            // let constantName = <initial value>

            let constInt = 42

            let constFloat = 2.11

            let constString = "string"

            print(constInt, constFloat, constString)

            

            // (2)类型标注 (添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称)

            // var constantName:<data type> = <optional initial value>

            let aaInt:Int = 2

            let aaFloat:Float = 3.1415926

            print(aaInt, "\n", aaFloat)

            

            // (3)常量命名 (由字母,数字和下划线组成, 以字母或下划线开始, 也可以使用简单的 Unicode 字符)

            let _const = "hello swift!"

            let 你好 = "你好世界"

            print(_const, "\n", 你好)

            print("\(_const) ...... \(你好)")

            

            // (4)常量输出

            // 变量和常量可以使用 printswift 2 print 替换了 println 函数来输出。

            // 字符串中可以使用括号与反斜线来插入常量

            let printName = "菜鸟教程"

            let printName2 = "http://www.runoob.com"

            

            print("\(printName)的官网地址为:\(printName2)")

            

    //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 2.变量 ---------------->

            // 变量是一种使用方便的占位符,用于引用计算机内存地址。

            // Swift 每个变量都指定了特定的类型,该类型决定了变量占用内存的大小,不同的数据类型也决定可存储值的范围。

            

            // (1)变量声明

            // 变量声明的意思是告诉编译器在内存中的哪个位置为变量创建多大的存储空间。

            // 使用 var 关键字声明

            // var variableName = <initial value>

            var varA = 42

            var varB:Float

            varB = 3.1415926

            varA += 1

            print(varA, varB)

            

            // (2)变量命名

            // 由字母、数字、下划线组成, 以字母或下划线开始,也可以使用简单的 Unicode 字符

            var _varA = "hellow swift!"

            _varA = "ni hao!"

            print(_varA)

            

            // (3)变量输出

            // 变量和常量可以使用 printswift 2 print 替换了 println 函数来输出。

            // 字符串中可以使用括号与反斜线来插入常量

            var _varB:NSString = "菜鸟教程"

            _varB = "菜鸟教程 "

            var _varC:NSString = "http://www.runoob.com"

            _varC = " http://www.runoob.com "

            print("\(_varB)的官网是:\(_varC)")

            

            

    //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->


            //<!----------- 3.数据类型 ---------------->

            // 使用数据类型存储不同的信息

            

            // (1) 内置数据类型

            // 常用数据类型 Int   UInt  浮点数  布尔值    字符串   字符   可选类型

            /**

                    Int   :  长度与当前平台的原生字长相同, 32(64)位平台上,IntInt32(Int64)长度相同,

                             32位平台上,Int可以存储的整数范围 -2,147,438,648~2,147,483,647

                    UInt  :  无符号整形,

                    浮点数 :  {

                                double : 64位浮点数, 最少15

                                float  : 32位浮点数, 最少6

                             }

                    布尔值 :  true , false

                    字符串字符串是字符的序列集合 "hellow swift!"

                    字符  :   指单个字母, “C”

                    可选类型 : 使用可选类型(optionals)来处理值可能缺失的情况,可选类型表示有值或没值

             */

            

            

            // (2) 数值范围

            /**

                类型         大小(字节)          区间值

                Int8          1字节            -127 ~ 127

                UInt8         1字节            0 ~ 255

                Int32         4字节            -2^31 ~ 2^31

                UInt32        4字节            0 ~ 2^32

                Int64         8字节            -9223372036854775808 ~ 9223372036854775807

                UInt64        8字节            0 ~ 18446744073709551615

                Float         4字节            1.2E-38 ~ 3.4E+38 (~6 digits)

                Double        8字节            2.3E-308 ~ 1.7E+308 (~15 digits)

             */

            

            

            // (3) 类型别名 : 类型别名对当前的类型定义了另一个名字,类型别名通过使用 typealias 关键字来定义

            // 语法格式   typealias newsname = type

            typealias zhengxing = Int

            let cccInt:zhengxing = 3

            print(cccInt)

            

            // (4) 类型安全 : 会在编译代码时进行类型检查(type checks), 把不匹配的类型标记为错误, 可以在开发时尽早发现修复错误

            var varCC = 42

            // varCC = "hellow swift!"  //报错 cannot assign value of type 'String' to type 'Int'

            varCC = 43

            print(varCC)

            

            

            // (5) 类型推断 : 如果没有显式的指定类型,swift会使用推断类型(type inference)来选择适合的类型

            let ddInt = 42  // ddInt 会被推断为 Int 类型

            let pi = 3.14159 // pi 会被推断为double类型, 浮点数的类型会推断为double, 不是float

            let pipi = 3 + 0.14159; // 表达式中同时出现整形和浮点数, 会被推断为double类型

            print(ddInt,pi,pipi)

            

            

            //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 4.字面量 ---------------->

            // 所谓字面量, 就是指特定的数字、字符串或者布尔值这样,能够直接的指出自己的类型并为变量进行赋值的值

            

            // (1) 整型字面量 : 可以是十进制、八进制、二进制或十六进制常量, 二进制前缀0b, 八进制前缀0o, 十六进制前缀0x

            let decimalInteger = 17         //17 十进制

            let binaryInteger = 0b10001     //17 二进制

            let octalInteger = 0o021        //17 八进制

            let hexadecimalInteger = 0x11   //17 十六进制

            print(decimalInteger,binaryInteger,octalInteger,hexadecimalInteger)

            

            // (2) 浮点型字面量 : 有整数部分,小数点,小数部分及指数部分

            // 浮点型字面量的默认推到类型为Double 表示64位浮点数

            // 十进制指数 :   1.25e2 表示 1.25*10^2 ,   1.25e-2 表示 1.25*10^-2  e E10^

            // 十六进制 :     0xFp2 表示 15*2^2  ,     (p P) 2^

            let decimalDouble = 12.1875      //十进制浮点型字面量

            let expontDouble = 1.21875e1     //十进制浮点型字面量

            let hexadecimalDouble = 0xC.3p0  //十六进制浮点型字面量

            print(decimalDouble,expontDouble,hexadecimalDouble)

            

            // (3)字符串型字面量 : 由被包在双引号中的一串字符串组成 "charaters"

            // 字符型字面量中不能包含未转义的双引号(“)、未转义的反斜线(\)、回车符或换行符

            /**

                 转移字符               含义

                 \0                 空字符

                 \\                 反斜线 \

                 \b                 退格(BS) ,将当前位置移到前一列

                 \f                 换页(FF),将当前位置移到下页开头

                 \n                 换行符

                 \r                 回车符

                 \t                 水平制表符

                 \v                 垂直制表符

                 \'                 单引号

                 \"                 双引号

                 \000               13位八进制数所代表的任意字符

                 \xhh...            12位十六进制所代表的任意字符

            */

            let stringL = "Hello\tWorld\n\n菜鸟教程官网:\'http://www.runoob.com\'"

            print(stringL)

            /** 输出

                 Hello World

                 

                 菜鸟教程官网:'http://www.runoob.com'

             */

            

            

            // (4)布尔型字面量 : 默认类型是Bool 

            // 布尔值字面量有三个值, swift的保留关键字: true:表示真,  false:表示假, nil:表示没有值

            

            

            //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 5.可选类型 ---------------->

            // swift的可选(optional)类型, 用于处理值缺失的情况, swift语言定义后缀问号 ? 作为命名类型optional的简写,例如以下两种声明相等

            /**

                   var optionalInteger: Int?

                   var optionalInteger: Optional<Int>

             */

            // 声明一个可选类型时,要确保用括号给?操作符一个适合的范围, 例如, 声明可选整数数组:(Int[])?,  不是Int[]?

            // 声明一个可选变量或者可选属性的时候没有提供初始值,它的值默认为nil

            // 如果一个可选类型的实例包含一个值,可以用后缀操作符!来访问这个值, 

            // 使用操作符!去获取值为nil的可选变量会有运行时错误, 可以用可选链接和可选绑定选择性执行可选表达式上的操作。如果值为nil,任何操作都不会执行,也不会有运行报错。

            /**

                    optionalInteger = 42

                    optionalInteger!  //42

        

                     var optionalInteger: Int?

                     optionalInteger = 42

                     print(optionalInteger!)

             */

            let ccString:String? = nil

            if ccString != nil {

                print(ccString)

            } else {

                print("字符串为 nil")

            }

            // 可选类型类似于OC中的指针的nil值, 但是nil只针对类(class)有用, 而可选类型对所有类型都可用,且更安全。

            

            // (1)强制解析 : 当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号(!)来获取值。这个感叹号表示"我知道这个可选有值,请使用它。"这被称为可选值的强制解析(forced unwrapping

            var cccStr:String?

            cccStr = "hellow swift!"

            if cccStr != nil {

                print(cccStr!,"\n",cccStr) // 强制解析

            } else {

                print("字符串为 nil")

            }

            /**输出

             hellow swift!    // 强制解析结果

             Optional("hellow swift!")

             

             注意:

             使用!来获取一个不存在的可选值会导致运行时错误。使用!来强制解析值之前,一定要确定可选包含一个非nil的值。

             */

            

            

            // (2)自动解析 : 你可以在声明可选变量时使用感叹号(!)替换问号(?)。这样可选变量在使用时就不需要再加一个感叹号(!)来获取值,它会自动解析

            var ccccString:String!

            ccccString = "自动解析。。。";

            if ccccString != nil {

                print(ccccString)

            } else {

                print("字符串为 nil")

            }

            /**输出

                自动解析。。。

             */

            

            

            // (3)可选绑定 : 使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在ifwhile语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。

            /**

                 if let constantName = someOptional {

                 statements

                 }

             */

            var cccccString:String?

            cccccString = "kexuanbangding...."

            if let CCCCString = cccccString {

                print(CCCCString)

            } else {

                print("字符串没有值");

            }

            

            

            //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 6.运算符 ---------------->

            // 运算符是一个符号, 用于告诉编译器执行一个数学或逻辑运算。

            /**

                算数运算符 : +   -   *   /   %   ++  --

                比较运算符号 : ==    !=   >    <    >=    <=    (结果为true, false)

                逻辑运算符 : &&      ||      !         (结果为true, false)

                位运算符 : 位运算符用来对二进制位进行操作, ~   &   |   ^   <<    >>

                         &(按位与,都为1时才为1,其他为0)     |(按位或,有一个为1就为1  ^(按位异或,相同为0,不同为1)

                         ~(按位取反)     <<(按位左移,将操作数的所有位向左移指定的位数, 空位用0补充)     >>(按位右移,)

                赋值运算符 : =   +=   -=   *=    /=  %=  <<=   >>=   &=    ^=    |=

                区间运算符 : 闭区间运算符(a...b)      半开区间运算符(a...

                其他运算符 : swift 提供了其他类型的的运算符,如一元、二元和三元运算符.

             */

            // 区间运算符

            print("闭区间运算符:")

            for index in 1...5 {

                print("\(index) * 2 = \(index * 2)")

            }

            print("半开区间运算符:")

            for index in 1..<5 {

                print("\(index) * 3 = \(index * 3)")

            }

            

            // 运算符优先级

            /**

                 指针最优,单目运算优于双目运算。如正负号。

                 先乘除(模),后加减。

                 先算术运算,后移位运算,最后位运算。请特别注意:1 << 3 + 2 & 7 等价于 (1 << (3 + 2))&7

                 逻辑运算最后计算

             */

            

            

            //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 7.条件语句 ---------------->

            /** 条件语句

                if 语句

                if...else 语句

                if...else if...else 语句

                内嵌 if 语句

                switch 语句

                

                ? : 运算符

             */

            

            

            

            //<!----------- 8.循环 ---------------->

            /** 循环类型

                for-in

                for 循环

                while 循环

                repeat...while 循环类似 while 语句区别在于判断循环条件之前,先执行一次循环的代码块

             */

            /** 循环控制语句

                continue 语句 

                break 语句

                fallthrough 语句如果在一个case执行完后,继续执行下面的case,需要使用fallthrough(贯穿)关键字

             */

            

            


            //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 9.字符串 ---------------->

            // swift 字符串是一系列字符的集合。例如 "Hello, World!" 这样的有序的字符类型的值的集合,它的数据类型为 String

            

            // (1)创建字符串

            // 是有字符串字面量

            let stringA = "hellow CJstring"

            print(stringA)

            // String 实例化

            let stringB = String("hellow shilihua...")

            print(stringB)

            

            // (2)空字符串

            // 可以使用空的字符串字面量赋值给变量或初始化一个String类的实例来初始值一个空的字符串。 可以使用字符串属性 isEmpty 来判断字符串是否为空:

            let stringAA = "" // 是有字符串字面量创建空字符串

            if stringAA.isEmpty {

                print("stringAA is empty....")

            } else {

                print("stringAA is not empty...")

            }

            

            let stringBB = String() // 实例化String 类来创建空字符串

            if stringBB.isEmpty {

                print("stringBB is empty....")

            } else {

                print("stringBB is not empty...")

            }

            

            // (3)字符串常量

            // 你可以将一个字符串赋值给一个变量或常量,变量是可修改的,常量是不可修改的。

            var stringAAA = "stringAAA is mutable..."  // stringAAA 可被修改

            stringAAA += "http://www.runoob.com"

            print(stringAAA)

            let stringBBB = String("stringBBB is can not mutable...") //

    //        stringBBB += "http://www.runoob.com"   // 报错 left side of mutating operator isn't mutable:'stringBBB' is a 'let' constant

            print(stringBBB)

            

            

            // (4)字符串中插入值

            // 字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。 您插入的字符串字面量的每一项都在以反斜线为前缀的圆括号中

            let varAaAA = 20

            let constaAAA = 100

            let varAaAAA:Float = 20.0

            let stringAaAA = "\(varAaAA) 乘以 \(constaAAA) 等于 \(varAaAAA * 100)"

            print(stringAaAA)

            

            // (5)字符串连接

            // 字符串可以通过 + 号来连接

            let lianjieA = "连接A..."

            let lianjieB = "连接B..."

            let lianjieC = lianjieA + lianjieB;

            print(lianjieC)

            

            // (6)字符串长度

            // String.characters.count 

            let changduA = "12345678"

            print("字符串长度为  \(changduA.characters.count)")

            

            // (7)字符串比较

            // 你可以使用 == 来比较两个字符串是否相等

            if lianjieA == lianjieB {

                

            } else {

                

            }

            

            // (8)Unicode 字符串

            // Unicode 是一个国际标准,用于文本的编码,Swift String 类型是基于 Unicode建立的。你可以循环迭代出字符串中 UTF-8 UTF-16 的编码

            let unicodeA = "你好吗!"

            print("UTF-8 编码:")

            for code in unicodeA.utf8 {

                print("\(code)","\n")

                

            }

            print("UTF-16 编码:")

            for code in unicodeA.utf16 {

                print("\(code)","\n")

            }

            

            // (9)字符串函数及运算符

            /**

                isEmpty :  判断字符串是否为空,返回布尔值

                hasPrefix(prefix: String) :  检查字符串是否拥有特定前缀

                hasSuffix(suffix: String) :  检查字符串是否拥有特定后缀。

                Int(String) :  转换字符串数字为整型

                String.characters.count  :  计算字符串的长度

                utf8  :  您可以通过遍历 String utf8 属性来访问它的 UTF-8 编码

                utf16  :  您可以通过遍历 String utf16 属性来访问它的 UTF-16 编码

                unicodeScalars :  您可以通过遍历String值的unicodeScalars属性来访问它的 Unicode 标量编码

                +  :   连接两个字符串,并返回一个新的字符串

                +=  :  连接操作符两边的字符串并将新字符串赋值给左边的操作符变量

                ==  :  判断两个字符串是否相等

                <  :   比较两个字符串,对两个字符串的字母逐一比较

                !=  :  比较两个字符串是否不相等

             

             */

            if CFStringHasPrefix(unicodeA, "") {

                print("CFStringHasPrefix.....YES")

            } else {

                print("CFStringHasPrefix.....NO")

            }

            if CFStringHasSuffix(unicodeA, "!") {

                print("CFStringHasSuffix.....YES")

            } else {

                print("CFStringHasSuffix.....NO")

            }

            let zhuanhuanInt:Int! = Int(changduA)

            print(zhuanhuanInt)

            

            print("标量编码:")

            for code in unicodeA.unicodeScalars {

                print("\(code)","\n")

            }

            

            

            //<!----------- 10.字符 ---------------->

            // Swift 的字符是一个单一的字符字符串字面量,数据类型为 Character

            let charA:Character = "A"

            print(charA)

            

            // (1)空字符变量 : Swift 中不能创建空的 Character(字符) 类型变量或常量

    //        let charAA:Character = ""   // "" 被推断为String类型

            

            // (2)遍历字符串中的字符

            for char in "hellow swift".characters {

                print(char)

            }

            

            // (3)字符串连接字符

            var charAA:String = "连接。。。"

            charAA.append(charA)

            print(charAA)

            

            

            //<!----------- 11.数组 ---------------->

            // Swift 数组使用有序列表存储同一类型的多个值

            

            // (1)创建数组

            // var someArray = [SomeType]()

            var arrayA = [String]()

            var arrayB = [String](count: 3,repeatedValue: "arrayB...  ")

            var arrayC = [10, 20, 30]

            

            // (2)访问数组 : 可以根据数组的索引来访问数组的元素  var someVar = someArray[index]

            var indexB = arrayB[0]

            var indexC = arrayC[1]

            indexB = "indexBBBB....."

            indexC += 40

            

            // (3)修改数组 : 可以使用 append() 方法或者赋值运算符 += 在数组末尾添加元素

            arrayA.append("arrayA... ")

            arrayA += [indexB]

            arrayA += ["\(indexC)"]

            arrayB[0] = "arrayBBBBB....."

            

            // (3)遍历数组 : 使用for-in循环来遍历所有数组中的数据项

            // 同时需要每个数据项的值和索引值,可以使用 String enumerate() 方法来进行数组遍历

            for item in arrayB {

                print(item)

            }

            for (index, item) in arrayB.enumerate() {

                print(index, item, "\n")

            }

            

            // (4)合并数组 : 使用加法操作符(+)来合并两种已存在的相同类型数组

            var arrayD = [String]()

            arrayD = arrayA + arrayB

            print("输出 arrayD : ", arrayD)

            

            // (5)count属性

            print("arrayD 的元素个数是 \(arrayD.count)")

            

            // (6)isEmpty属性

            print("arrayD 是否为空 \(arrayD.isEmpty)")

            

            

            //<!----------- 12.字典 ---------------->

            // 字典 : 用来存储无序的相同类型数据的集合

            

            // (1)创建字典 :   

            /**

                var someDict =  [KeyType: ValueType]()   创建一个特定类型的空字典

             */

            var dicA = [String: String]()

            var dicB = [Int: String]()

            dicA = ["a":"1", "b":"2", "c":"3"]

            dicB = [0:"a1", 1:"b2", 2:"c3"]

            print(dicA, dicB)

            

            let dicC:[Int:String] = [5:"five...", 6:"six...", 0:"a1"]

            print(dicC)

            

            // (2)访问字典 :   var someVar = someDict[key]

            let keyA:String! = dicA["a"]

            print(keyA)

            

            // (3)修改字典 : 使用 updateValue(forKey:) 增加或更新字典的内容。如果 key 不存在,则添加值,如果存在则修改 key 对应的值

            dicA.updateValue("d", forKey: "4")

            dicA["a"] = "11111"

            print(dicA)

            

            // (4)移除Key-Value : 可以使用 removeValueForKey() 方法来移除字典 key-value 对。如果 key 存在该方法返回移除的值,如果不存在返回 nil

            // 可以通过指定键的值为 nil 来移除 key-value(键-值)对

            dicB.removeValueForKey(1)

            dicB[0] = nil

            print(dicB)

            

            // (5)遍历字典

    //        for (key, value) in dicB {   // 两种都可以

            for (key, value) in dicB.enumerate() {

                print("字典:key : \(key),   value: \(value)")

            }

            

            // (6)字典转换为数组 : 可以提取字典的键值(key-value)对,并转换为独立的数组

            let dicKeyA = [String](dicA.keys)

            let dicValueA = [String](dicA.values)

            print("dicA的键key : \(dicKeyA)")

            print("dicA的值Value : \(dicValueA)")

            

            // (7)属性 : count , isEmpty

            print("字典dicB的元素个数: \(dicB.count)......")

            print("字典dicB是否为空 \(dicB.isEmpty).....")

            

            

            

            

    //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 13.函数 ---------------->

            // Swift 函数用来完成特定任务的独立的代码块, 使用一个统一的语法来表示简单的C语言风格的函数到复杂的Objective-C语言风格的方法

            /**

                 函数声明: 告诉编译器函数的名字,返回类型及参数。

                 函数定义: 提供了函数的实体。

             */

            // Swift 函数包含了 参数类型 返回值类型

            

            // (1)函数定义  (2)函数调用

            /** 定义函数使用关键字 func 语法

                 func funcname(形参) -> returntype

                 {

                     Statement1

                     Statement2

                     ……

                     Statement N

                     return parameters

                 }

             */

            func resetNickname(userName:String) -> String { // 定义函数

                var name:String! = userName

                name.appendContentsOf("...........")

                return name

            }

            print(resetNickname("phoebe_zhang")) // 调用

            

            // (3)函数参数 : 函数可以接受一个或者多个参数,我们也可以使用元组(tuple)向函数传递一个或多个参数

            func refreshDidView(model1:Int, model2:Int) -> Int {

                return model1 * model2

            }

            print(refreshDidView(3, model2: 5))

            

            // (4)不带参数函数

            /** 语法

                 func funcname() -> datatype {

                     return datatype

                 }

             */

            func refreshNoti() {

                

            }

            refreshNoti()

            

            // (5)元组作为函数返回值 :

            // 元组与数组类似,不同的是,元组中的元素可以是任意类型,使用的是圆括号, 你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回

            func minMax(arrayA:[Int]) -> (minA:Int, maxA:Int)? {

               

                if arrayA.isEmpty { 

                    return nil

                }

                

                var min = arrayA[0]

                var max = arrayA[0]

                

                for item in arrayA {

                    

                    if item < min {

                        min = item

                    } else if (max < item) {

                        max = item

                    }

                    

                }

                

                return (min, max)

            }

            let minArray:[Int] = [1,6,8,3,12,45,78,0]

            let valueArrayy = minMax(minArray)!

            print("数组arrayA min : ", valueArrayy.minA, "\n", "数组arrayA max: ", valueArrayy.maxA)

            print("min : \(valueArrayy.minA) ,  max : \(valueArrayy.maxA)")

            // 可选元组类型  (Int, Int)?与元组包含可选类型如(Int?, Int?)是不同的.可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值。

            

            // (6)没有返回值函数

            func readMyName(myName:String) {

                print(myName)

            }

            readMyName("phoebe_zhangxiaoping...")

            

            // (7)函数参数名称 : 函数参数都有一个外部参数名和一个局部参数名

            /**

                局部参数名称 : 在函数内部使用 , (例如 myName为局部参数名,只能在函数体内使用

                外部参数名称 : 可以在局部参数名前指定外部参数名,中间以空格分隔,外部参数名用于在函数调用时传递给函数的参数

             */

            func readName(name myName: String, nickName myNickmane: String) {

                print(myName, myNickmane)

            }

            readName(name: "zhangxiaoping", nickName: "phoebe")

            

            // (8)可变参数 : 可变参数可以接受零个或多个值。函数调用时,你可以用可变参数来指定函数参数,其数量是不确定的

            // 可变参数通过在变量类型名后面加入(...)的方式来定义

            func readNickName(yourNicknam: String...) {

                print(yourNicknam)

            }

            readNickName("你的昵称  ", "Phoebe", "nickname") // 输出 :  ["你的昵称  ", "Phoebe", "nickname"]

            

            // (9)常量,变量及I/O参数

            //  一般默认在函数中定义的参数都是常量参数,也就是这个参数你只可以查询使用,不能改变它的值

            // 一般默认的参数传递都是传值调用的,而不是传引用。 所以传入的参数在函数内改变,并不影响原来的那个参数。传入的只是这个参数的副本

            /**

                (* swift 3 中要删除此方法)  func  getName(var id:String).......   : 如果想要声明一个变量参数,可以在前面加上var,这样就可以改变这个参数的值了

                inout 关键字 :  In-Out Parameters 输入输出参数,如果你想要一个函数可以修改参数的值,且想要在这些修改在函数调用结束后仍然存在,则定义为输入输出参数

             */

            /** swift 3 中将要删除此方法

                 func addAB(var a:Int, var b:Int) {

                 a *= 2

                 b *= 2

                 print("\(a) * \(b) = \(a*b)")

                 }

                 addAB(10, b: 10)

             */

            var inoutA = 10

            var inoutB = 20

            func inoutAB( a:inout Int, b:inout Int) {

                a *= 2

                b *= 2

                let c = a + b

                print("a*2 + b*2 = \(c)")

            }

            print("原始值:",inoutA, inoutB)

            inoutAB(&inoutA, b: &inoutB)

            print("改变后:", inoutA, inoutB)

            

            // (10)函数类型及使用 : 每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成

            // 使用函数类型 : 你可以定义一个类型为函数的常量或变量,并将适当的函数赋值给它

            /**

                var addition: (Int, Int) -> Int = sum  

                解析定义一个叫addition的变量,参数与返回的类型均为Int 并让这个新变量指向sum函数。

                sum addition 有同样的类型,所以以上操作是合法的

             */

            func sum(a: Int, b: Int) -> Int {

                return a+b

            }

            let addAABB:(Int, Int) -> Int = sum

            print(addAABB(10,20))

            

            // (11)函数类型作为参数类型、函数类型作为返回类型

            // 可以将函数作为参数传递给另外一个参数

            

            func subA(a: Int, b: Int) -> Int {

                return a-b

            }

            // var subB:(Int, Int) -> Int = subA

            let subB = subA

            print("20 - 10 = ", subB(20,b: 10))

            

            func subC(subA: (_ a: Int, _ b: Int)->Int, c: Int, d: Int) {

                print("30 - 20 = ", subA(a: c, b: d))

            }

            subC(subA, c: 30, d: 20)

            

            // (12)函数嵌套 : 函数嵌套指的是函数内定义一个新的函数,外部的函数可以调用函数内定义的函数

            func nestA(a: Int, b: Int) -> Int {

                

                func nestB(c: Int)->Int {

                    return c*2

                }

                

                let d = nestB(10)

                print("d = \(d)")

                

                return nestB(a) + nestB(b)

            }

            let e = nestA(10, b: 20)

            print("eeeeeeee ======  \(e)")

            

            

            

    //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 14.枚举 ---------------->

            /**

                 它声明在类中,可以通过实例化类来访问它的值。

                 枚举也可以定义构造函数(initializers)来提供一个初始成员值;可以在原始的实现基础上扩展它们的功能。

                 可以遵守协议(protocols)来提供标准的功能

                 enum enumname {

                 // 枚举定义放在这里

                 }

                * 注意 : Swift 的枚举成员在被创建时不会被赋予一个默认的整型值

             */

            

            // (1)语法 :

            var weekDay = DayssofaWeek.WEDNESDAY

            weekDay = .WEDNESDAY

            switch weekDay {

            case .Sunday:

                print("周日")

            case .WEDNESDAY:

                print("周三")

            default:

                print("周六")

            }

            

            // (2)相关值 : 以下实例中定义一个名为 Student 的枚举类型,它可以是 Name 的一个相关值(IntIntInt),或者是 Mark 的一个字符串类型(String)相关值

            let stuNames = Student.Name("ZhangSan")

            let stuMarks = Student.Mark(98, 97, 95)

            switch stuMarks {

            case .Name(let stuName):

                print("学生的名字是: \(stuName)")

            case .Mark(let Mark1, let Mark2, let Mark3):

                print("学生的成绩是: \(Mark1), \(Mark2), \(Mark3)")

            } // 输出结果   学生的成绩是: 98,97,95

            print(stuNames)

            

            // 原始值 : 原始值可以是字符串,字符,或者任何整型值或浮点型值

            // 在原始值为整数的枚举时,不需要显式的为每一个成员赋值,Swift会自动为你赋值。

            // 例如,当使用整数作为原始值时,隐式赋值的值依次递增1。如果第一个值没有被赋初值,将会被自动置为0

            /**

                 enum Month: Int {

                     case January = 1, February, March, April, May, June, July, August, September, October, November, December

                 }

             */

            let weekday1 = DayssofaWeek.WEDNESDAY.hashValue

            print(weekday1)  // 输出: 3

            

            

            //<!----------- 15.结构体 ---------------->

            // 可以为结构体定义属性(常量、变量)和添加方法,从而扩展结构体的功能

            /** 区别于COC:

                 结构体不需要包含实现文件和接口。

                 结构体允许我们创建一个单一文件,且系统会自动生成面向其它代码的外部接口。

             */

            // 结构体总是通过被复制的方式在代码中传递,因此它的值是不可修改的

            

            // (1)语法 : 关键字 struct

            /**

                 struct nameStruct {

                     Definition 1

                     Definition 2

                     ……

                     Definition N

                 }

             */

            struct sturentsMarksStruct {

                var English:Int = 100

                var Chines:Int = 99

                var math:Int = 98

            }

            // 我们可以通过结构体名来访问结构体成员。结构体实例化使用 let 关键字:

            let myMarks = sturentsMarksStruct()

            print("我的成绩是:", myMarks.English, myMarks.math, myMarks.Chines)

            

            // 以下实例化通过结构体实例化时传值并克隆一个结构体

            struct YourMarksStruct {

                var mark : Int

                

                init(mark: Int) {

                    self.mark = mark

                }

            }

            var aStruct = YourMarksStruct(mark: 99)

            aStruct.mark = 100

            var bStruct = aStruct

            bStruct.mark = 97

            print(aStruct.mark, bStruct.mark) // 100, 97

            

            // (2)结构体应用

            // 结构体实例总是通过值传递来定义你的自定义数据类型

            /** 按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:

                    结构体的主要目的是用来封装少量相关简单数据值。

                    有理由预计一个结构体实例在赋值或传递时,封装的数据将会被拷贝而不是被引用。

                    任何在结构体中储存的值类型属性,也将会被拷贝,而不是被引用。

                    结构体不需要去继承另一个已存在类型的属性或者行为。

             */

            // 结构体实例是通过值传递而不是通过引用传递

            

            

            //<!----------- 16. ---------------->

            // (1)类与结构体对比

            /** 与结构体相比,类还有如下的附加功能:

                 继承允许一个类继承另一个类的特征

                 类型转换允许在运行时检查和解释一个类实例的类型

                 解构器允许一个类实例释放任何其所被分配的资源

                 引用计数允许对一个类的多次引用

             */

            /** 语法

                 Class classname {

                     Definition 1

                     Definition 2

                     ……

                     Definition N

                 }

             */

            

            // (2)作为引用类型访问类属性 : 类的属性可以通过 . 来访问。格式为:实例化类名.属性名

            

            // (3)恒等运算符

            // 因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。

            /** 为了能够判定两个常量或者变量是否引用同一个类实例,Swift 内建了两个恒等运算符:

                 恒等运算符                                         不恒等运算符

                 运算符为:===                                      运算符为:!==

                 如果两个常量或者变量引用同一个类实例则返回 true         如果两个常量或者变量引用不同一个类实例则返回 true

             */

            

            

            

            //<!----------- 17.属性 ---------------->

            // Swift 属性将值跟特定的类、结构或枚举关联。  属性可分为存储属性和计算属性

            /**

                 存储属性                               计算属性

                 存储常量或变量作为实例的一部分             计算(而不是存储)一个值

                 用于类和结构体                          用于类、结构体和枚举

             */

            

            // (1)存储属性 : 简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。

            

            // (2)延迟存储属性 : 延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用 lazy 来标示一个延迟存储属性。

            /**

             * 注意:

             必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。

             */

            

            // (3)实例化变量 : 一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。

            

            // (4)计算属性 : 除存储属性外,类、结构体和枚举可以定义计算属性,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值

            

            // (5)只读计算属性 : 只有 getter 没有 setter 的计算属性就是只读计算属性

            // 必须使用var关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。

            

            // (6)属性观察器 : 属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。

            

            // (7)全局变量和局部变量 : 计算属性和属性观察器所描述的模式也可以用于全局变量和局部变量

            /**

                 局部变量                               全局变量

                 在函数、方法或闭包内部定义的变量。          函数、方法、闭包或任何类型之外定义的变量。

                 用于存储和检索值。                       用于存储和检索值。

                 存储属性用于获取和设置值。                 存储属性用于获取和设置值。

                 也用于计算属性。                         也用于计算属性。

             */

            

            // (8)类型属性 : 类型属性是作为类型定义的一部分写在类型最外层的花括号({})内。

            // 使用关键字 static 来定义值类型的类型属性,关键字 class 来为类定义类型属性。

            struct Teachers {

                static var English = ""

                static var computedTypeProperty:Int {

                    return 3

                }

            }

            

            enum TYpessss {

                static var TypeAA = ""

                static var TypeBB:Int {

                    return 3

                }

                

                func typeDid(a:Int) -> Int {

                    print(">>>>>> 枚举中定义方法:", a)

                    

                    return a*2

                }

                

            }

            

            class CLASSsss {

                class var classAAA: Int {

                    return 3

                }

            }

            

            // (9)获取和设置类型属性的值 : 类似于实例的属性,类型属性的访问也是通过点运算符(.)来进行。但是,类型属性是通过类型本身来获取和设置,而不是通过实例

            

            

            

    //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 18.方法 ---------------->

            // Swift 方法是与某些特定类型相关联的函数

            // Objective-C 中,类是唯一能定义方法的类型。但在 Swift 中,你不仅能选择是否要定义一个类/结构体/枚举,还能灵活的在你创建的类型(类/结构体/枚举)上定义方法。

            

            // (1)实例方法

            /** 语法 :

                 func <#name#>(<#parameters#>) -> <#return type#> {

                 <#function body#>

                 }

             */

            print(aAddB(100, b: 200))

            countADD(100)

            print(countA)

            

            // 方法的局部参数名称和外部参数名称 : Swift 默认仅给方法的第一个参数名称一个局部参数名称;默认同时给第二个和后续的参数名称为全局参数名称

            // 例如 aAddB 方法中,a 为局部参数名称, b 用于全局的声明并通过外部程序访问。

            

            // 是否提供外部名称设置 : 我们强制在第一个参数添加外部名称把这个局部名称当作外部名称使用(Swift 2.0前是使用 # 号)。

            // 相反,我们呢也可以使用下划线(_)设置第二个及后续的参数不提供一个外部名称

            func paramA(first a:Int, b:Int) {

                print("\(a+b)")

            }

            paramA(first: 10, b: 10)

            

            func paramB(a:Int, second _b:Int) {

                print("\(a-_b)")

            }

            paramB(10, second: 5)

            

            

            // (2)self 属性 : 类型的每一个实例都有一个隐含属性叫做selfself 完全等同于该实例本身。

            // 你可以在一个实例的实例方法中使用这个隐含的self属性来引用当前实例。

            

            self.countA = 100

            print(self.countA)

            

            // (3)在实例方法中修改值类型变异(mutating)

            /**

                 Swift 语言中结构体和枚举是值类型。一般情况下,值类型的属性不能在它的实例方法中被修改。

                 但是,如果你确实需要在某个具体的方法中修改结构体或者枚举的属性,你可以选择变异(mutating)这个方法,然后方法就可以从方法内部改变它的属性;并且它做的任何改变在方法结束时还会保留在原始结构中。

                 方法还可以给它隐含的self属性赋值一个全新的实例,这个新实例在方法结束后将替换原来的实例。

             */

            var mutaMarks = MarkStruct(English: 99, Chines: 99, Math: 95)

            print(">>>>> 英语 ", mutaMarks.English)

            

            mutaMarks.subMarks(100, math: 90)

            print(">>>>> 英语...... ", mutaMarks.English)

            

            // (4)在可变方法中给self赋值 : 可变方法能够赋给隐含属性 self 一个全新的实例。  mutating

            

            // (5)类型方法 : 实例方法是被类型的某个实例调用的方法,你也可以定义类型本身调用的方法

            // 声明结构体和枚举的类型方法,在方法的func关键字之前加上关键字static    static

            // 类可能会用关键字class来允许子类重写父类的实现方法。      class

            // 类型方法和实例方法一样用点号(.)语法调用

            let minmarkss = MarkStruct.minMarks(90, math: 80)

            print(minmarkss)

            

            //<!--------------- 关键字static class 的区别 -------------->

            // class关键字除了有自定义类的作用, 还有声明类方法的作用

            // (1)在方法的func关键字之前加上关键字static或者class都可以用于指定类方法.

            // (2)不同的是用class关键字指定的类方法可以被子类重写, 但是用static关键字指定的类方法是不能被子类重写的

            // (3)类方法和实例方法可以重名

            

            

            //<!----------- 19.下标脚本 ---------------->

            /**

                 下标脚本 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。

                 举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 someArray[index] ,访问字典(Dictionary)实例中的元素可以这样写 someDictionary[key]

                 对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个

             */

            

            // (1)下标脚本语法及应用 :

            /** 语法 :

                 subscript(index: Int) -> Int {

                     get {

                         // 用于下标脚本值的声明

                     }

                     set(newValue) {

                         // 执行赋值操作

                     }

                 }

             */

            let subscriMark = MarkStruct(English: 100, Chines: 100, Math: 100)

            print("100/10 = ", subscriMark[10])

            print("100/20 = ", subscriMark[20])

            

            let p = ViewController2()

            print(p[0],"\n")

            

            // 用法通常下标脚本是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式。

            // 你可以在你自己特定的类或结构体中自由的实现下标脚本来提供合适的功能

            

            // (2)下标脚本选项

            /**

                 下标脚本允许任意数量的入参索引,并且每个入参类型也没有限制。

                 下标脚本的返回值也可以是任何类型。

                 下标脚本可以使用变量参数和可变参数。

                 一个类或结构体可以根据自身需要提供多个下标脚本实现,在定义下标脚本时通过传入参数的类型进行区分,使用下标脚本时会自动匹配合适的下标脚本实现运行,这就是下标脚本的重载。

             */

            print("下标脚本重载: 10*2+2 = ",subscriMark[10,2])

            

            

            //<!----------- 20.继承 ---------------->

            // 子类, 超类(或父类)

            // Swift 中,类可以调用和访问超类的方法,属性和下标脚本,并且可以重写它们。

            

            // (1)基类 : 没有继承其它类的类,称之为基类(Base Class

            

            // (2)子类 : 子类指的是在一个已有类的基础上创建一个新的类

            

            // (3)重写 : Overriding, 子类可以通过继承来的实例方法,类方法,实例属性,或下标脚本来实现自己的定制功能,我们把这种行为叫重写

            /**

                 重写             访问方法,属性,下标脚本

                 方法             super.somemethod()

                 属性             super.someProperty()

                 下标脚本          super[someIndex]

             */

            

            // (4)重写方法和属性

            // 重写方法 :

            let superStudent = StudentDetails()

            superStudent.recordMarks()

            

            let subTom = Tom()

            subTom.recordMarks()

            // 重写属性 : 你可以提供定制的 getter(或 setter)来重写任意继承来的属性,无论继承来的属性是存储型的还是计算型的属性

            /** 注意

                 如果你在重写属性中提供了 setter,那么你也一定要提供 getter

                 如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接通过super.someProperty来返回继承来的值,其中someProperty是你要重写的属性的名字。

             */

            subTom.English = 100

            //subTom.Math = 120 // get-only

            print("重写属性:tom  ", subTom.Math)

            

            // (5)重写属性观察器 : 你可以在属性重写中为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会监测到。

            // 注意:你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。

            subTom.English = 200

            print(">>>> 重写:", subTom.Chines, subTom.Math)

            

            // (6)防止重写 : final,  我们可以使用 final 关键字防止它们被重写

            // 如果你重写了final方法,属性或下标脚本,在编译时会报错。

            // 你可以通过在关键字class前添加final特性(final class)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。

            

            

            

            

            // 构造过程是为了使用某个类、结构体或枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务

            // 构造函数 : init()  ,  Object-C中的构造器不同, swift的构造函数无需返回值, 它们的主要任务是保证新实例在第一次使用前完成正确的初始化

            // 类实例也可以通过定义析构器(deinitializer)在类实例释放之前执行清理内存的工作。

            

            // (1)存储型属性的初始赋值 : 在实例创建时,必须为所有存储型属性设置合适的初始值。

            // 存储属性在构造器中赋值时,它们的值是被直接设置的,不会触发任何属性观测器。

            /** 存储属性在构造器中赋值流程:

                 创建初始值。

                 在属性定义中指定默认属性值。

                 初始化实例,并调用 init() 方法。

             */

            

            // (2)构造器 : init    构造器在创建某特定类型的新实例时调用。它的最简形式类似于一个不带任何参数的实例方法,以关键字init命名。

            /** 语法 :

                    init() {

                        // 实例化后执行的代码

                    }

             */

            //实例 : 以下结构体定义了一个不带参数的构造器 init,并在里面将存储型属性 length breadth 的值初始化为 6 12

            struct AinitaStruct {

                var length:Double

                var width:Double

                

                var r = 3.5  // (3)默认属性值

                

                init() {

                    length = 5.5

                    width = 9

                }

            }

            let areaA = AinitaStruct()

            print("矩形的面积:\(areaA.length * areaA.width)")

            

            // (3)默认属性值 : 我们可以在构造器中为存储型属性设置初始值;同样,也可以在属性声明时为其设置默认值。

            // 使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型。

            

            // (4)构造参数 : 你可以在定义构造器 init() 时提供构造参数,如下所示:

            struct AparamStruct {

                var length : Double

                var width : Double

                var area : Double

                

                init(fromLength length: Double, fromWidth width: Double) {

                    self.length = length

                    self.width = width

                    area = length * width

                }

                

                init(fromLg lg: Double, fromWd wd: Double) {

                    self.length = lg

                    self.width = wd

                    area = lg * wd

                }

            }

            let areaPA = AparamStruct(fromLength: 10, fromWidth: 20)

            let areaPB = AparamStruct(fromLg: 100, fromWd: 200)

            let areaPC = AparamStruct.init(fromLength: 5, fromWidth: 10)

            print("areaPA:\(areaPA.area),   areaPB:\(areaPB.area),   areaPC:\(areaPC)")

            

            // (5)内部和外部参数名 : 如果你在定义构造器时没有提供参数的外部名字,Swift 会为每个构造器的参数自动生成一个跟内部名字相同的外部名。

            struct Color {

                let red, green, blue: Double

                init (red: Double, green: Double, blue: Double) {

                    self.red = red

                    self.green = green

                    self.blue = blue

                }

                

                init(white: Double) {

                    red = white

                    green = white

                    blue = white

                }

            }

            let purpleColor = Color.init(red: 255, green: 222, blue: 111)

            let yellowColor = Color.init(white: 200)

            print(purpleColor.red, yellowColor.red)

            

            // 没有外部参数名称 : 如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线_来显示描述它的外部名

            struct ColorNO {

                let red: Double

                init(_ white: Double) {

                    red = white

                }

            }

            let noColorA = ColorNO.init(100)

            print(">>>>>>>>  没有外物参数: noColorA = ", noColorA.red)

            

            // (6)可选属性类型 : 如果你定制的类型包含一个逻辑上允许取值为空的存储型属性,你都需要将它定义为可选类型optional type(可选属性类型)。

            // 当存储属性声明为可选时,将自动初始化为空 nil

            struct RGB {

                var red : Double?

                let green : Double? // (7)green属性现在是常量

        

                init(white: Double) {

                    red = white + 10

                    green = red! + 10 // (7)仍然可以在构造器中设置值

                }

                

                init(_ black: Double) {

                    red = black

                    green = red! + 100

                }

            }

            let RGBa = RGB.init(white: 100)

            let RGBb = RGB.init(200)

            // print(RGBa.red, RGBb.red) // 输出结果 Optional(110.0) Optional(200.0)

            print(RGBa.red!, RGBb.red!) // 输出结果 110.0 200.0

            

            // (7)构造过程中修改常量属性 : 只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值

            // 对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改

            

            // (8)默认构造器 : 默认构造器将简单的创建一个所有属性值都设置为默认值的实例

            // 以下实例中,ShoppingListItem类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器

            let item = ShoppingListItem()

            print("默认构造器: ", item.name, item.quantity, item.purchased)  // 输出结果: 默认构造器:  nil 1 false

            

            // 结构体的逐一成员构造器 : 如果结构体对所有存储型属性提供了默认值且自身没有提供定制的构造器,它们能自动获得一个逐一成员构造器。

            // 我们在调用逐一成员构造器时,通过与成员属性名相同的参数名进行传值来完成对成员属性的初始赋值。

            struct Shopping {

                var length = 100.0

                var width = 200.0

            }

            let shopA = Shopping.init(length: 33.0, width: 24.0)

            print("结构体的逐一成员变量: ", shopA.length*shopA.width)

            

            // (9)值类型的构造器代理 : 构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复。

            // 以下实例中,RectA 结构体调用了 SizeA PointA 的构造过程:

            struct SizeA {

                var width = 0.0, height = 0.0

            }

            struct PointA {

                var x = 0.0, y = 0.0

            }

            struct RectA {

                var origin = PointA()  // origin属性使用定义时的默认值PointA(x: 0.0, y: 0.0)

                var size = SizeA()

                

                init() {}

                init(origin: PointA, size: SizeA) {

                    self.origin = origin

                    self.size = size

                }

                

                init(center: PointA, size: SizeA) {

                    //先通过centersize的值计算出origin的坐标

                    let originX = center.x - size.width/2

                    let originY = center.y  - size.height/2

                    //然后再调用(或代理给)init(origin:size:)构造器来将新的originsize值赋值到对应的属性中

                    self.init(origin: PointA.init(x: originX, y: originY), size: size)

                }

            }

            let rectA = RectA()

            print("PointA 结构体初始值: \(rectA.origin.x, rectA.origin.y)"// 输出结果 PointA 结构体初始值: (0.0, 0.0)

            // originsize的参数值赋给对应的存储型属性

            let rectB = RectA.init(origin: PointA(x: 56.0, y: 45.0), size: SizeA(width: 100.0, height: 200.0))

            print("PointB 结构体初始值: \(rectB.origin.x, rectB.origin.y)"// 输出结果 PointB 结构体初始值: (56.0, 45.0)

            //先通过centersize的值计算出origin的坐标。

            //然后再调用(或代理给)init(origin:size:)构造器来将新的originsize值赋值到对应的属性中

            let rectC = RectA.init(center: PointA(x: 10.0, y: 10.0), size: SizeA(width: 24.0, height: 25.0))

            print("PointC 结构体初始值: \(rectC.origin.x, rectC.origin.y)"// 输出结果 PointC 结构体初始值: (-2.0, -2.5)

          

            /** 构造器代理规则 :

             值类型  : 不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给本身提供的其它构造器。 可以使用self.init在自定义的构造器中引用其它的属于相同值类型的构造器。

             类类型  :  它可以继承自其它类,这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。

             */

            

            // (10)类的继承和构造过程 : Swift 提供了两种类型的类构造器来确保所有类实例中 存储型属性 都能获得初始值,它们分别是指定构造器和便利构造器。

            /** 

                指定构造器类中最主要的构造器

                            初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。

                            每一个类都必须拥有至少一个指定构造器

                             Init(parameters) {

                                 statements

                             }

                便利构造器类中比较次要的、辅助型的构造器

                            可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入的实例。

                            只在必要的时候为类提供便利构造器

                             convenience init(parameters) {

                                 statements

                             }

             */

            let yuebing = Mooncake.init(huaMei: "华美月饼")

            let yuebing1 = Ronglang.init(huaMei: "华美月饼", rongLang: "荣朗月饼")

            print(">>>> 华美: \(yuebing.huamei), \n, >>>>> 华美: \(yuebing1.huamei), \n, >>>>> 荣朗: \(yuebing1.ronglang)")

            

            let car = carCalss(aoDI: "奥迪。。。")

            // let aodi = AODIClass(aoDI: "奥迪、、、", daZhong: "大众、、、")

            let aodi = AODIClass.init(aoDI: "奥迪")

            print("car: \(car.aodi) \n AODI: \(aodi.aodi, aodi.dazhong)")

            

            // (11)构造器的继承和重载 : Swift 中的子类不会默认继承父类的构造器

            // 父类的构造器仅在确定和安全的情况下被继承。 当你重写一个父类指定构造器时,你需要写override修饰符。

            let wine = WineClass()

            print(wine.desccription)  // 输出结果 红酒 不错!

            let redwine = REDWineClass()

            print(redwine.desccription) // 输出结果 红酒名酒。。。 不错!

            

            // 指定构造器和便利构造器实例 : 接下来的例子将在操作中展示指定构造器、便利构造器和自动构造器的继承。

            // 它定义了包含两个个类MainClassSubClass的类层次结构,并将演示它们的构造器是如何相互作用的。

            let game = GameClass(mobilegame: "精灵宝")

            print("game : \(game.mobileGames)") // 输出结果: game : 精灵宝

            let game1 = GameClass()

            print("game none : \(game1.mobileGames)") // 输出结果:  game none : 逐鹿天下手游

            

            let mobile = MobileGameClass.init(mobilegame: "纪念碑谷")

            print("mobile one : \(mobile.mobileGames)") // 输出结果: mobile one : 纪念碑谷

            let mobile1 = MobileGameClass.init(moblegame: "梦幻西游", zhulu: "酷跑")

            print("mobile1 two : \(mobile1.zhuluGame)") // 输出结果:  mobile1 two : 酷跑

            

            // (12)类的可失败构造器 : 如果一个类,结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器。

            // 其语法为在init关键字后面加添问号(init?)

            /** 变量初始化失败可能的原因有:

                 传入无效的参数值。

                 缺少某种所需的外部资源。

                 没有满足特定条件。

             */

            struct GameStruct {

                let game: String

                

                init?(zhulu: String) {

                    

                    if zhulu.isEmpty {

                        return nil

                    } else {

                        self.game = zhulu

                    }

                }

            }

            //通过该可失败构造器来构建一个GameStruct的对象,并检查其构建过程是否成功

            // gameZhulu 的类型是 GameStruct?   而不是 GameStruct

            let gameZhulu = GameStruct.init(zhulu: "逐鹿天下,》》》")

            if let zhulu = gameZhulu {

                print("可失败构造器: \(zhulu.game)")

            }

            // 枚举类型的可失败构造器

            

            // (13)覆盖一个可失败构造器 

            // 就如同其它构造器一样,你也可以用子类的可失败构造器覆盖基类的可失败构造器。

            // 者你也可以用子类的非可失败构造器覆盖一个基类的可失败构造器。

            // 你可以用一个非可失败构造器覆盖一个可失败构造器,但反过来却行不通。

            // 一个非可失败的构造器永远也不能代理调用一个可失败构造器。

            let plName = planet(name: "Mercury")

            print("行星的名字是:\(plName.name)"// 行星的名字是: Mercury

            let nopName = planet()

            print("没有这个星星的名字:\(nopName.name)"// 没有这个名字的行星: [No Planets]

            

            // (14)可失败构造器 init!

            // 通常来说我们通过在init关键字后添加问号的方式(init?)来定义一个可失败构造器,但你也可以使用通过在init后面添加惊叹号的方式来定义一个可失败构造器(init!)

            let stmaek = StuRecord(stname: "Runoob")

            if let name = stmaek {

                print("指定了学生名:\(name)") // 指定了学生名:

            }

            let blankname = StuRecord(stname: "")

            if blankname == nil {

                print("学生名为空") // 学生名为空

            }

            

            

            //<!----------- 22.析构过程 ---------------->

            // deinit : 在一个类的实例被释放之前,析构函数被立即调用。用关键字deinit来标示析构函数,类似于初始化函数用init来标示。析构函数只适用于类类型。

            /** 析构过程原理

                 Swift 会自动释放不再需要的实例以释放资源。

                 Swift 通过自动引用计数(ARC)处理实例的内存管理。

                 通常当你的实例被释放时不需要手动地去清理。但是,当使用自己的资源时,你可能需要进行一些额外的清理。

                 例如,如果创建了一个自定义的类来打开一个文件,并写入一些数据,你可能需要在类实例被释放之前关闭该文件。

             */

            /** 语法 : 在类的定义中,每个类最多只能有一个析构函数。析构函数不带任何参数,在写法上不带括号:

                 deinit {

                    // 执行析构过程

                 }

             */

            var show: BaseClass? = BaseClass()

            var hide: BaseClass? = BaseClass.init()

            print("有值: ", counter)  // 输出: 有值:  2

            show = nil   // show = nil 语句执行后,计算器减1show占用的内存就会释放。

            hide = nil

            print("置空:", counter) // 输出: 置空: 0

            print(show, hide) // 输出:   nil nil

            

            

            

            //<!----------- 23.自动引用计数(ARC ---------------->

            // ARC  这一机制跟踪和管理应用程序的内存。 通常不需要手动释放内存,因为 ARC 会在类的实例不再被使用时,自动释放其占用的内存

            /** ARC 功能:

                 init() ,  当每次使用 init() 方法创建一个类的新的实例的时候,ARC 会分配一大块内存用来储存实例的信息。

                 内存中包含实例的类型信息, 以及这个实例所有相关属性的值

                 当实例不再被使用时,ARC 释放实例所占用的内存,并让释放的内存能挪作他用。

                 为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。

                 实例赋值给属性、常量或变量,它们都会创建此实例的强引用,只要强引用还在,实例是不允许被销毁的。

             */

            // 值会被自动初始化为nil, 目前还不会引用到BaseClass类的实例

            var baseC : BaseClass?

            var baseC1 : BaseClass?

            var baseC2 : BaseClass?

            // 创建BaseClass类的实例

            baseC = BaseClass()

            // 赋值给其他两个变量,该实例又会多出两个强引用

            baseC1 = baseC

            baseC2 = baseC

            // 断开第一个强引用

            baseC = nil

            // 断开第二个强引用

            baseC1 = nil

            // 断开第三个强引用,并调用析构函数

            baseC2 = nil

            print(baseC1, baseC2)

            // 在上面的例子中,ARC 会跟踪你所新创建的 BaseClass 实例的引用数量,并且会在 BaseClass 实例不再被需要时销毁它

          

            // *** 类实例之间的循环强引用

            // *** 类实例之间的循环强引用

            // 一个类永远不会有0个强引用,这种情况发生在两个类实例相互保持对方的强引用,并让对方不被销毁,这就是所谓的循环强引用

            

            // 两个变量都被初始化为nil

            var basesingcalss : SignClass?

            var basessclass : SSClass?

            // 赋值

            basesingcalss = SignClass.init(name: "BaseSignClass")

            basessclass = SSClass.init(number: 73)

            // 意感叹号是用来展开和访问可选变量 runoob number73 中的实例

            // 循环强引用被创建

            basesingcalss!.baseSs = basessclass

            basessclass!.baseSign = basesingcalss

            // 断开basesingcalss basessclass 变量所持有的强引用时,引用计数并不会降为0 实例也不会被 ARC 销毁

            // 注意, 当你把这两个变量设置为nil时,没有任何一个析构函数被调用

            // 强引用循环阻止了SignClassSSClass类实例的销毁, 并在你的应用程序中造成了内存泄露

            basesingcalss = nil

            basessclass = nil

            print("循环请引用", basesingcalss, basessclass)

            

            // 解决实例之间的循环强引用 weak 弱引用,  unowned 无主引用

            // 此两种引用允许循环引用中的一个实例引用另外一个实例而不保持强引用,这样实例能够相互引用而不产生循环强引用

            // 对于生命周期中会变为nil的实例使用弱引用,相反的, 对于初始化赋值后再也不会被赋值为nil的实例, 使用无主引用。

            // 弱引用实例

            var toc : Module?

            var list : SubModul?

            toc = Module.init(name: "ARC")

            list = SubModul.init(number: 4)

            toc!.sub = list

            list!.topic = toc

            toc = nil

            list = nil

            print("弱引用", basesingcalss, basessclass)

            // 无主引用实例

            var peter : StudentPeter?

            peter = StudentPeter.init(name: "Peter")

            peter!.section = MarkPeter.init(marks: 99, stname: peter!)

            peter = nil

            

            // *** 闭包引起的循环强引用

            // *** 闭包引起的循环强引用

            // 当你将一个闭包赋值给类实例的某个属性, 并且这个闭包体中又使用了实例。这个闭包体中可能访问了实例的某个属性,例如self.someProperty 或者闭包中调用了实例的某个方法,例如self.someMethod 这两种情况导致了闭包捕获”self 从而产生了循环引用。

            // 创建实例并打印信息

            var paragraph: HTMLElement?

            paragraph = HTMLElement.init(name: "pp", text: "hellow, world")

    //        print(paragraph!.asHTML)

            // 解决闭包引起的循环强引用 : 在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用

            /** 弱引用和无主引用

                 当闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。

                 相反的,当捕获引用有时可能会是nil时,将闭包内的捕获定义为弱引用。

                 如果捕获的引用绝对不会置为nil,应该用无主引用,而不是弱引用。

             */

            print(paragraph!.asasHTML())

            // HTMLElement实例将会被销毁,并能看到它的析构函数打印出的消息

            paragraph = nil

            

            

            

            //<!----------- 24.类型转换 ---------------->

            /** 检测 is  转换 as

                 Swift 语言类型转换可以判断实例的类型。也可以用于检测实例类型是否属于其父类或者子类的实例。

                 Swift 中类型转换使用 is as 操作符实现,is 用于检测值的类型,as 用于转换类型。

                 类型转换也可以用来检查一个类是否实现了某个协议。

             */

            // (1)定义一个类层次

            // 类型转换用于检测实例类型是否属于特定的实例类型

            // 你可以将它用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。

            class Subjects {

                var physics : String

                

                init(physics : String) {

                    self.physics = physics

                }

            }

            

            class Chemistry : Subjects {

                var equations : String

                

                init(physics: String, equations: String) {

                    self.equations = equations

                    super.init(physics: physics)

                }

                

            }

            

            class Maths: Subjects {

                var formulae : String

                

                init(physics : String, formulae : String) {

                    self.formulae = formulae

                    super.init(physics: physics)

                }

                

            }

            

            let sa = [Chemistry(physics: "固体物理", equations: "赫兹"),

                      Maths(physics: "流体动力学", formulae: "千兆赫"),

                      Maths(physics: "流体动力学", formulae: "千兆赫"),]

            let samplechem = Chemistry.init(physics: "固体物理", equations: "赫兹")

            print("实例物理学史: \(samplechem.physics)")

            print("实例方程式: \(samplechem.equations\(sa[0].physics)")

            

            let samplemaths = Maths(physics: "流体动力学", formulae: "千兆赫")

            print("实例物理学是: \(samplemaths.physics)")

            print("实例公式是: \(samplemaths.formulae)")

            

            // 2)检查类型 : 关键字 is

            // 操作符 is 来检查一个实例是否属于特定子类型。若实例属于那个子类型,类型检查操作符返回 true,否则返回 false

            var chemCount = 0

            var mathsCount = 0

            for item in sa {

                if item is Chemistry {

                    chemCount += 1

                } else {

                    mathsCount += 1

                }

            }

            print("化学科目包含: \(chemCount)个, 数学包含: \(mathsCount)个主题") // 化学科目包含: 1个, 数学包含: 2个主题

            

            // (3)向下转型 : as? as!

            // as?   当你不确定向下转型可以成功时,用类型转换的条件形式(as?)。条件形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 nil

            // as!   只有你可以确定向下转型一定会成功时,才使用强制形式(as!)。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。

            for item in sa {

                

                // 类型转换的条件形式

                if let show = item as? Chemistry {

                    print("化学主题是: '\(show.physics)', \(show.equations)")

             

                    // 强制形式

                } else if let example = item as? Maths {

                    print("数学主题是: '\(example.physics)',  \(example.formulae)")

                }

            }

            

            // (4)Any AnyObject的类型转换

            // AnyObject : 可以代表任何class类型的实例 ,  Any 可以代表任何类型,包括方法类(function types)

            // 注意: 只有当你明确的需要它的行为和功能时才使用AnyAnyObject。在你的代码里使用你期望的明确的类型总是更好的

            

            // Any 实例 :

            // 可以存储Any类型的数组 exampleany

            var exampleany = [Any]()

            exampleany.append(12)

            exampleany.append(3.14159)

            exampleany.append("Any 实例")

            exampleany.append(Chemistry(physics: "固体物理", equations: "赫兹"))

            

            for item in exampleany {

                switch item {

                case let someInt as Int :

                    print("整型值为 \(someInt)")

                    

                case let someDouble as Double :

                    print("Pi 值为 \(someDouble)")

                

                case let someString as String :

                    print("\(someString)")

                    

                case let phy as Chemistry:

                    print("主题 '\(phy.physics)', \(phy.equations)")

                    

                default:

                    print("None")

                }

            }

            

            // AnyObject 实例 

            let saprint : [AnyObject] = [Chemistry.init(physics: "11", equations: "aa"),

                                         Maths.init(physics: "22", formulae: "bb"),

                                         Chemistry.init(physics: "33", equations: "cc"),

                                         Maths.init(physics: "44", formulae: "dd")]

            for item in saprint {

                // 类型转换的条件形式

                if let show = item as? Chemistry {

                    print("化学主题是: '\(show.physics)', \(show.equations)")

                    // 强制形式

                } else if let example = item as? Maths {

                    print("数学主题是: '\(example.physics)',  \(example.formulae)")

                }

            }

            

            

            

            //<!----------- 25.扩展 ---------------->

            // 扩展就是向一个已有的类、结构体或枚举类型添加新的功能

            // 扩展可以对一个已有的类型添加新的功能, 但是不能重写已有的功能

            /** swift中的扩展可以:

                 添加计算型属性和计算型静态属性

                 定义实例方法和类型方法

                 提供新的构造器

                 定义下标

                 定义和使用新的嵌套类型

                 使一个已有类型符合某个协议

             */

            /** 语法 : 关键字 extension

                 extension SomeType {

                    // 加到SomeType的新功能写在这里

                 }

             

                 一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议,语法格式如下

                 extension SomeType: SomeProtocol, AnotherProctocol {

                     // 协议实现写到这里

                 }

             */

            

            // (1)计算型属性 : 扩展可以向已有类型添加计算型实例属性和计算型类型属性。

            let addition = 3.add

            print("加法运算后的值: \(addition)"// 输出: 加法运算后的值: 103

            

            // (2)构造器  :  扩展可以向已有类型添加新的构造器。

            // 这可以让你扩展其它类型,将你自己的定制类型作为构造器参数,或者提供该类型的原始实现中没有包含的额外初始化选项。

            // 扩展可以向类中添加新的便利构造器 init(),但是它们不能向类中添加新的指定构造器或析构函数 deinit()

            

            // (3)方法 : 扩展可以向已有类型添加新的实例方法和类型方法。

            4.topics ({

                print("扩展模块内")

            })

            1.topics({

                print("内型转换模块内")

            })

            2.topics { 

                print("222222")

            }

            

            // (4)可变实例方法 : 通过扩展添加的实例方法也可以修改该实例本身。

            // 结构体和枚举类型中修改self或其属性的方法必须将该实例方法标注为mutating,正如来自原始实现的修改方法一样

            var trail1 = 2.3

            trail1.square()

            print("圆的面积: \(trail1)")

            

            // (5)下标扩展可以向一个已有类型添加新下标。

            print(12[0])  // 输出  2

            

            // (6)嵌套类型 : 扩展可以向已有的类、结构体和枚举添加新的嵌套类型:

            

            

            //<!----------- 26.协议 ---------------->

            // 协议规定了用来实现某一特定功能所必需的方法和属性。  任意能够满足协议要求的类型被称为遵循(conform)这个协议。

            // 类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能

            /** 语法

                 protocol SomeProtocol {

                     // 协议内容

                 }

             *//**

                 要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号:分隔,作为类型定义的一部分。遵循多个协议时,各协议之间用逗号,分隔。

                 struct SomeStructure: FirstPotocol, AontherProtocol {

                     // 结构体内容

                 }

             

                 如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔。

                 class SomeClass: SomeSuperClass, FirstPotocol, AontherProtocol {

                     // 类内容

                 }

             */

            

            // (1)对属性的规定 : 协议用于指定特定的实例属性或类属性,而不用指定是存储型属性或计算型属性。此外还必须指明是只读的还是可读可写的

            // 协议中的通常用var来声明变量属性,在类型声明后加上{ set get }来表示属性是可读可写的,只读属性则用{ get }来表示。

            let studentH = classc()

            studentH.stname = "swift"

            studentH.marks = 98

            studentH.marksseucred()

            print(studentH.marks, studentH.result, studentH.present, studentH.subject, studentH.stname)

            

            // (2) Mutating 方法的规定 : 有时需要在方法中改变它的实例。

            // 例如,值类型(结构体,枚举)的实例方法中,将mutating关键字作为函数的前缀,写在func之前,表示可以在该方法中修改它所属的实例及其实例属性的值。

            var res = days.wed

            res.show()

            

            // (3)对构造器的规定 : 协议可以要求它的遵循者实现指定的构造器。

            // 你可以像书写普通的构造器那样,在协议的定义里写下构造器的声明,但不需要写花括号和构造器的实体,语法如下:

            /** 语法

                 protocol SomeProtocol {

                     init(someParameter: Int)

                 }

             */

            

            // (3)协议构造器规定在类中的实现

            // 你可以在遵循该协议的类中实现构造器,并指定其为类的指定构造器或者便利构造器。在这两种情况下,你都必须给构造器实现标上"required"修饰符:

            /** 语法 :   required

                 class SomeClass: SomeProtocol {

                     required init(someParameter: Int) {

                         // 构造器实现

                     }

                 }

             */

            // 使用required修饰符可以保证:所有的遵循该协议的子类,同样能为构造器规定提供一个显式的实现或继承实现。

            // required,override : 如果一个子类重写了父类的指定构造器,并且该构造器遵循了某个协议的规定,那么该构造器的实现需要被同时标示requiredoverride修饰符:

            

            let af = mClass.init(aprot: 23)

            let afshow = sClass.init(no1: 32, no2: 31)

            print("af is : \(af.no1)", "afshow is \(afshow.no1)")

            

            //(4)协议类型 : 尽管协议本身并不实现任何功能,但是协议可以被当做类型来使用

            /** 协议可以像其他普通类型一样使用,使用场景:

                 作为函数、方法或构造器中的参数类型或返回值类型

                 作为常量、变量或属性的类型

                 作为数组、字典或其他容器中的元素类型

             */

            var itemsss = [10,20,30].generate()

            while let x = itemsss.next() {

                print(x)

            }   // 输出  10 20 30

            for lists in [1,2,3].map({i in i*5}) {

                print(lists)

            }  // 输出  5  10  15

            

            // (5)在扩展中添加协议成员

            // 我们可以可以通过扩展来扩充已存在类型(类,结构体,枚举等) 扩展可以为已存在的类型添加属性,方法,下标脚本,协议等成员。

            

            // (6)协议的继承协议能够继承一个或多个其他协议,可以在继承的协议基础上增加新的内容要求。

            /** 协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔:

                 protocol InheritingProtocol: SomeProtocol, AnotherProtocol {

                     // 协议定义

                 }

             */

            

            // (7)类专属协议 : class,   你可以在协议的继承列表中,通过添加class关键字,限制协议只能适配到类(class)类型。

            /** class关键字必须是第一个出现在协议的继承列表中,其后,才是其他继承协议。格式如下:

                 protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {

                     // 协议定义

                 }

             */

        

            // (8)协议合成 : Swift 支持合成多个协议,这在我们需要同时遵循多个协议时非常有用。

            /** 语法格式 :

                 protocol<SomeProtocol, AnotherProtocol>

             */

            func showand(celebrator: Stname & Stage) {

                print("\(celebrator.name) is \(celebrator.age) years old")

            }

            let snameaa = PerSonsss.init(name: "Priya", age: 20)

            showand(snameaa)  // 输出结果  Priya is 20 years old

            

            // (9)检验协议的一致性 : 你可以使用isas操作符来检查是否遵循某一协议或强制转化为某一类型。

            /**

                 is操作符用来检查实例是否遵循了某个协议。

                 as?返回一个可选值,当实例遵循协议时,返回该协议类型;否则返回nil

                 as用以强制向下转型,如果强转失败,会引起运行时错误。

             */

            let objectsprotocol:[AnyObject] = [

            Circle(radius: 2.0),

            Country(area: 234),

            Animal(legs: 23)]

            for object in objectsprotocol {

                if let objectAraea = object as? HasArea {

                    print("面积是:\(objectAraea.area)")

                } else {

                    print("没有面积")

                }

            } // 输出结果  面积是:12.566   面积是:234.0   没有面积

            

            

            

            //<!----------- 27.泛型 ---------------->

            // swift提供了泛型让你写出灵活且可重用的函数和类型,  swift标准库是通过泛型代码构建出来的,  swift的数组和字典都是泛型,

            // 你可以创建一个Int数组,也可创建一个String数组,或者甚至于可以是任何其他 Swift 的类型数据数组。

            // 以下实例是一个非泛型函数 exchange 用来交换两个 Int 值:

            func  exchange( a:inout Int, b:inout Int) {

                let temp = a

                a = b

                b = temp

            }

            var numb1 = 20

            var numb2 = 30

            print("交换前数据: \(numb1) \(numb2)")

            exchange(&numb1, b: &numb2)

            print("交换后数据: \(numb1) \(numb2)")

            

            // 泛型函数可以访问任何类型, Int String

            // 以下实例是一个泛型函数 exchange 用来交换两个 Int String :

            func exchangefanxing<T>( a: inout T, b: inout T) {

                let temp = a

                a = b

                b = temp

            }

            var excnumb1 = 100

            var excnumb2 = 200

            print("交换前数据\(excnumb1) \(excnumb2)")

            exchangefanxing(&excnumb1, b: &excnumb2)

            print("交换后数据: \(excnumb1) \(excnumb2)")

            

            var excstr1 = "AAA"

            var excstr2 = "BBB"

            print("交换前数据\(excstr1) \(excstr2)")

            exchangefanxing(&excstr1, b: &excstr2)

            print("交换后数据: \(excstr1) \(excstr2)")

            /**

                  这个函数的泛型版本使用了占位类型名字(通常此情况下用字母T来表示)来代替实际类型名(如IntStringDouble)。

                  占位类型名没有提示T必须是什么类型,但是它提示了ab必须是同一类型T,而不管T表示什么类型。

                  只有 exchange(_:_:)函数在每次调用时所传入的实际类型才能决定T所代表的类型。

             

                 另外一个不同之处在于这个泛型函数名后面跟着的占位类型名字(T)是用尖括号括起来的()。

                 这个尖括号告诉 Swift 那个T exchange(_:_:)函数所定义的一个类型。因为T是一个占位命名类型,Swift 不会去查找命名为T的实际类型。

             */

            

            // (1)泛型类型 : Swift 允许你定义你自己的泛型类型。

            // 自定义类、结构体和枚举作用于任何类型,如同ArrayDictionary的用法。

            var tos = TOS<String>()

            tos.push("swift")

            print(tos.items)

            

            tos.push("泛型")

            print(tos.items)

            

            let deleteos = tos.pop()

            print(deleteos, "aaa")

            

            // (2)扩展泛型类型 : extension, 你并不需要在扩展的定义中提供类型参数列表

            // 原始类型定义中声明的类型参数列表在扩展里是可以使用的,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。

            if let first = tos.first {

                print("栈顶部:\(first)")

            }

            

            // (3)类型约束 : 指定了一个必须继承自指定类的类型参宿,或者遵循一个特定的协议或协议构成

            /** 类型约束语法

                 可以写一个在一个类型参数名后面的类型约束,通过冒号分割,来作为类型参数链的一部分。这种作用于泛型函数的类型约束的基础语法如下所示

                 func someFunction<T: SomeClass, U:SomeProtocol>(someT: T, someU: U) {

                     // 这里是函数主体

                 }

             */

            func findStringIndex(array: [String], _ valueToFind: String) -> Int? {

                for (index, value) in array.enumerate() {

                    if value == valueToFind {

                        return index

                    }

                }

                

                return nil

            }

            let stringsss = ["cat", "dog", "llama", "parakeet", "terrapin"]

            if let foundIndex = findStringIndex(stringsss, "llama") {

                print("llama 的下标是 \(foundIndex)")

            }

            

            // (4)关联类型实例 : typealias 关键字用来设置关联类型

            // 定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。

            var tos1 = TOSCon<String>()

            tos1.push("swift1")

            print(tos1.items)

            

            tos1.push("泛型1")

            print(tos1.items)

            

            tos1.push("参数类型1")

            print(tos1.items)

            

            tos1.push("类型参数名1")

            print(tos1.items)

            

            // (5)Where 语句

            /**

                 类型约束能够确保类型符合泛型函数或类的定义约束。

                 你可以在参数列表中通过where语句定义参数的约束。

                 你可以写一个where语句,紧跟在在类型参数列表后面,where语句后跟一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型间的等价(equality)关系。

             

                 // swift 3.0 之前版本写法

                 func allItemsMatch<C1: Container, C2: Container

                 where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>(someContainer: C1, anotherContainer: C2) -> Bool {

             */

            func allItemsMatch<C1: Container, C2: Container>(someContainer: C1, anotherContainer: C2) -> Bool

                where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {

                

                // 检查两个Container的元素个数是否相同

                if someContainer.count != anotherContainer.count {

                    return false

                }

                

                // 检查两个Container相应位置的元素彼此是否相等

                for i in 0..<someContainer.count {

                    if someContainer[i] != anotherContainer[i] {

                        return false

                    }

                }

                

                // 匹配所有项,返回 true

                return true

            }

            var ttt = Stack<String>()

            ttt.push("Swift2")

            print(ttt.items)

            

            ttt.push("泛型2")

            print(ttt.items)

            

            ttt.push("Where 语句2")

            print(ttt.items)

            

            var eos = ["Swift", "泛型", "Where 语句"]

            print(eos)

            

            

            //<!----------- 28.访问控制 ---------------->

            /** swift 为代码中的实体提供了三种不同的访问级别:publicinternalprivate

                 访问级别                   定义

                 Public             可以访问自己模块中源文件里的任何实体,别人也可以通过引入该模块来访问源文件里的所有实体。

                 Internal           可以访问自己模块中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。

                 Private            只能在当前源文件中使用的实体,称为私有实体。

            

             */// public为最高级访问级别,private为最低级访问级别

            /** 语法

                 public class SomePublicClass ()

                 Internal calss SomeInternalClass ()

                 private class SomePrivareClass ()

             

                 public var somePlubilcVariable = 0

                 Internal let someInteralConstant = 0

                 private func somePrivateFunction() {}

             */// 除非有特殊的说明,否则实体都使用默认的访问级别internal

            

            // (1)函数类型访问权限 : 函数的访问级别需要根据该函数的参数类型和返回类型的访问级别得出。

            /** 下面的例子定义了一个名为someFunction全局函数,并且没有明确地申明其访问级别

                 func someFunction() -> (SomeInternalClass, SomePrivareClass) {

                     // 函数实体

                 }

             

             函数中其中一个类 SomeInternalClass 的访问级别是internal,另一个 SomePrivateClass 的访问级别是private。所以根据元组访问级别的原则,该元组的访问级别是private

             因为该函数返回类型的访问级别是private,所以你必须使用private修饰符,明确的声明该函数:

                 private func someFunction() -> (SomeInternalClass, SomePrivateClass) {

                     // 函数实现

                 }

             将该函数申明为publicinternal,或者使用默认的访问级别internal都是错误的。

             */

            

            // (2)枚举类型访问权限 : 枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员单独申明不同的访问级别。

            var stuAll = StudentAll.Name("swift")

            var stualla = StudentAll.Mark(99,98,97)

            switch stualla {

            case .Name(let stuName):

                print("学生:\(stuName)")

            case .Mark(let math, let English, let Chines):

                print("学生的成绩:\(math), \(English), \(Chines)")

            }

            

            // (3)子类访问权限 : 子类的访问级别不得高于父类的访问级别。比如说,父类的访问级别是internal,子类的访问级别就不能申明为public

            let sup = superClassss()

            sup.show()

            

            let sub = ssClassss()

            sub.show

            

            // (4)常量、变量、属性、下标访问权限 : 常量、变量、属性不能拥有比它们的类型更高的访问级别。下标也不能拥有比索引类型或返回类型更高的访问级别。

            // private var privateInstance = SomePrivateClass()

            

            // (5)Getter Setter 访问权限 : 常量、变量、属性、下标索引的GettersSetters的访问级别继承自它们所属成员的访问级别

            // Setter的访问级别可以低于对应的Getter的访问级别,这样就可以控制变量、属性或下标索引的读写权限。

            let newCounter = samplegm()

            newCounter.counter = 100

            newCounter.counter = 800

            // 输出结果: 计数器: 100 新增加数量 100    计数器: 800 新增加数量 700

            

            // (6)构造器和默认构造器访问权限

            /**

                初始化: 我们可以给自定义的初始化方法申明访问级别,但是要不高于它所属类的访问级别。但必要构造器例外,它的访问级别必须和所属类的访问级别相同

                如同函数或方法参数,初始化方法参数的访问级别也不能低于初始化方法的访问级别。

             

                默认初始化方法: Swift为结构体、类都提供了一个默认的无参初始化方法,用于给它们的所有属性提供赋值操作,但不会给出具体值。

                                默认初始化方法的访问级别与所属类型的访问级别相同。

             */

            let ababab = classAa()

            let babab = clssAb() //输出结果:  10  30  10

            

            // (7)协议访问权限: 如果想为一个协议明确的申明访问级别,那么需要注意一点,就是你要确保该协议只在你申明的访问级别作用域中使用。

            // 如果你定义了一个public访问级别的协议,那么实现该协议提供的必要函数也会是public的访问级别。这一点不同于其他类型,比如,public访问级别的其他类型,他们成员的访问级别为internal

            

            // (8)扩展访问权限: 扩展成员应该具有和原始类成员一致的访问级别。比如你扩展了一个公共类型,那么你新加的成员应该具有和原始成员一样的默认的internal访问级别。

            // 或者,你可以明确申明扩展的访问级别(比如使用private extension)给该扩展内所有成员申明一个新的默认访问级别。这个新的默认访问级别仍然可以被单独成员所申明的访问级别所覆盖

            

            // (9)泛型访问权限: 泛型类型或泛型函数的访问级别取泛型类型、函数本身、泛型类型参数三者中的最低访问级别。


            // (10) 类型别名: 任何你定义的类型别名都会被当作不同的类型,以便于进行访问控制。一个类型别名的访问级别不可高于原类型的访问级别。

            // 注意:这条规则也适用于为满足协议一致性而给相关类型命名别名的情况。

            

            

            

            

    //<!------------------------------------------ 我是可爱的分割线 --------------------------------------------------->

            

            //<!----------- 29.闭包 ---------------->

            // 闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。

            // 全局函数和嵌套函数其实就是特殊的闭包。

            /** 闭包形式有:

             全局函数                 嵌套函数                     闭包表达式

             有名字但不能捕获任何值。 有名字,也能捕获封闭函数内的值。 无名闭包,使用轻量级语法,可以根据上下文环境捕获值。

             */

            /** Swift中的闭包有很多优化的地方:

                 根据上下文推断参数和返回值类型

                 从单行表达式闭包中隐式返回(也就是闭包体只有一行代码,可以省略return

                 可以使用简化参数名,如$0, $1(0开始,表示第i个参数...)

                 提供了尾随闭包语法(Trailing closure syntax)

             

              语法:

                 {(parameters) -> return type in

                     statements

                 }

             */

            let divde = {(val1: Int, val2: Int) -> Int in

                return val1 / val2

            }

            let result1 = divde(200, 20)

            print(result1) // 输出结果: 10

            

            // (1)闭包表达式: 闭包表达式是一种利用简洁语法构建内联闭包的方式。 

            // sort 函数 :

            let nameall = ["AT", "AE", "D", "S", "BE"]

            func backwards(s1: String, s2: String) -> Bool { // 使用普通函数(或内嵌函数)提供排序功能,闭包函数类型需为(String, String) -> Bool

                return s1 > s2

            }

            var reversed = nameall.sort(backwards)

            print(reserved)  // 输出结果:  ["S", "D", "BE", "AT", "AE"]

            

            // (2)参数名称缩写: Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过$0,$1,$2来顺序调用闭包的参数。

            var reversed1 = nameall.sort( { $0 > $1 } )  // $0$1表示闭包中第一个和第二个String类型的参数。

            print(reversed1) // 输出:  ["S", "D", "BE", "AT", "AE"]

            

            // (3)运算符函数: 实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。

            var reversed2 = nameall.sort(>)  // Swift String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。 而这正好与sort(_:)方法的第二个参数需要的函数类型相符合。 因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现:

            print(reversed2) // 输出:  ["S", "D", "BE", "AT", "AE"]

            

            // (4)尾随闭包: 尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用

            /**

                 func someFunctionThatTakesAClosure(closure: () -> Void) {

                     // 函数体部分

                 }

                 

                 // 以下是不使用尾随闭包进行函数调用

                 someFunctionThatTakesAClosure({

                     // 闭包主体部分

                 })

                 

                 // 以下是使用尾随闭包进行函数调用

                 someFunctionThatTakesAClosure() {

                     // 闭包主体部分

                 }

             

             // 注意: 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把()省略掉。var reversed3 = nameall.sort { $0 > $1}

             */

            var reversed3 = nameall.sort() { $0 > $1}

            print(reversed3) // 输出:  ["S", "D", "BE", "AT", "AE"]

            

            // (5)捕获值

            

            // (6)闭包是引用类型:

            

            

            

            //<!----------- 30.可选链 ---------------->

            // Optional Chaining,  是一种可以请求和调用属性、方法和子脚本的过程,用于请求或调用的目标可能为nil

            /** 可选链返回两个值:

                 如果目标有值,调用就会成功,返回该值

                 如果目标为nil,调用将返回nil

             */// 多次请求或调用可以被链接成一个链,如果任意一个节点为nil将导致整条链失效

            

            // (1)可选链可替代强制解析 :  ? !

            

            // (2)为可选链定义模型类: 你可以使用可选链来多层调用属性,方法,和下标脚本。这让你可以利用它们之间的复杂模型来获取更底层的属性,并检查是否可以成功获取此类底层属性

            

            // (3)通过可选链调用方法: 你可以使用可选链的来调用可选值的方法并检查方法调用是否成功。即使这个方法没有返回值,你依然可以使用可选链来达成这一目的。

            

            // (4)使用可选链调用下标脚本

            

            // (5)通过可选链接调用来访问下标

            

            // (6)访问可选类型的下标: 如果下标返回可空类型值,比如SwiftDictionarykey下标。可以在下标的闭合括号后面放一个问号来链接下标的可空返回值:

            

            // (7)连接多层链接

            

            // (8)对返回可选值的函数进行链接: 我们还可以通过可选链接来调用返回可空值的方法,并且可以继续对可选值进行链接。

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

            

        }


        override func didReceiveMemoryWarning() {  // 重写父类方法

            super.didReceiveMemoryWarning()

            // Dispose of any resources that can be recreated.

        }


        /************* 实例方法 **************/

        func aAddB(a:Int, b:Int) -> Int//(实例方法)

            return a+b

        }

        

        var countA = 0

        func countADD(addCount:Int) { //(实例方法)

            countA += addCount

        }

        

       

     


    }





    //-----------------------------------------------------------------------------------------------------------------//

    //-----------------------------------------------------------------------------------------------------------------//


    class ViewController2: UIViewController {

        

        private var daysdays = ["Sun", "Mun", "Tue", "Wed", "Thu", "Fri", "Sat"]

        subscript(index:Int) -> String {

            get {

                return daysdays[index]  // 声明下标脚本语言

            }

            set(newValue) {

                self.daysdays[index] = newValue  // 执行赋值操作

            }

        }

        

    }



    //-----------------------------------------------------------------------------------------------------------------//

    //-----------------------------------------------------------------------------------------------------------------//


    class StudentDetails {    // (1)基类, 没有继承其它类的类,称之为基类(Base Class)。

        

        var English = 99  // 默认值,

        var Math: Int {

            return English - 5

        }

        

        

        func recordMarks() {

            print("父类中的方法>>>>>>")

        }

        

    }



    class Tom: StudentDetails { // (2)子类, 子类指的是在一个已有类的基础上创建一个新的类

        

        var Chines = 10

        

        override var English: Int {

            didSet {

               Chines = English / 2

            }

        }

        

        override var Math: Int// get-only

            return super.Math - 5

        }


        

        override func recordMarks() {

            super.recordMarks()

            

            print("子类中的重写>>>>>>>")

        }

    }




    //-----------------------------------------------------------------------------------------------------------------//

    //-----------------------------------------------------------------------------------------------------------------//


    // 1)构造过程

    class ShoppingListItem {  // 以下实例中,ShoppingListItem类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器

        var name : String?

        var quantity = 1

        var purchased = false

        

    }


    // 2)指定构造器实例

    class Mooncake {

        var huamei: String // 局部存储变量

        init(huaMei: String) {

            self.huamei = huaMei // 初始化

        }

    }


    class Ronglang: Mooncake {

        var ronglang : String // 新的子类存储变量

        

        init(huaMei: String, rongLang: String) { // 初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化

         

            self.ronglang = rongLang // 初始化

            super.init(huaMei: huaMei)  // 初始化超类

        }

        

    }


    // (3)便利构造器实例

    class carCalss {

        var aodi: String // 局部存储变量

        

        init(aoDI: String) {

            self.aodi = aoDI // 初始化

        }

    }


    class AODIClass: carCalss {

        var dazhong: String

        

        init(aoDI: String, daZhong: String) {

            

            self.dazhong = daZhong

            super.init(aoDI: aoDI)

        }

        

        // 便利方法只需要一个参数

        override convenience init(aoDI: String) {

            self.init(aoDI: aoDI, daZhong: "")

        }

    }


    // (4)构造器的继承和重载

    class WineClass {

        var redWine = "红酒"

        var desccription: String {

            return "\(redWine) 不错!"

        }

    }


    class REDWineClass: WineClass {

        

        override init() { // 重载构造器

            super.init()

            redWine = "红酒名酒。。。"

        }

    }


    // (5)指定构造器和便利构造器 继承实例

    class GameClass {

        var mobileGames: String

       

        init(mobilegame: String) {

            self.mobileGames = mobilegame

        }

        

        convenience init() {

            self.init(mobilegame: "逐鹿天下手游")

        }

    }


    class MobileGameClass: GameClass {

        var zhuluGame : String

        

        init(moblegame: String, zhulu: String) {

            

            self.zhuluGame = zhulu

            super.init(mobilegame: moblegame)

        }

        

        override convenience init(mobilegame: String) {

            self.init(moblegame: mobilegame, zhulu: "逐鹿")

        }

        

    }


    // (6) 可失败构造器

    class planet {

        var name : String

        

        init(name: String) {

            self.name = name;

        }

        

        convenience init () {

            self.init(name: "[No Planets]")

        }

    }


    class planets: planet {

        var count : Int

        

        init(name: String, count: Int) {

            self.count = count

            super.init(name: name)

        }

        

        override convenience init(name: String) {

            self.init(name: name, count: 1)

        }

        

    }


    // (7)可失败构造器 init!

    struct StuRecord {

        let stname : String

        

        init!(stname: String) {

            if stname.isEmpty {

                return nil

            }

            self.stname = stname

        }

        

    }


    // (8)析构过程

    var counter = 0; // 引用计数器

    class BaseClass {

        init() {

            counter += 1;

        }

        

        deinit {

            counter -= 1;

        }

    }


    // (9)循环强引用

    class SignClass {

        let name : String

        

        init(name : String) {

            self.name = name

        }

        

        var baseSs : SSClass?

        

        deinit {

            print(" #\(name) 被析构")   // 循环强引用, 不会被调用

        }

        

    }


    class SSClass {

        let number : Int

        

        init(number: Int) {

            self.number = number

        }

        

        var baseSign : SignClass?

        

        deinit {

            print("SSClass #\(number) 被析构"// 循环强引用, 不会被调用

        }

        

    }


    // (10)弱引用实例

    class Module {

        let name : String

        init(name: String) {

            self.name = name

        }

        

        var sub : SubModul?

        

        

        deinit {

            print(" \(name) 主模块 被析构") // 弱引用, 会被调用

        }

    }


    class SubModul {

        let number : Int

        

        init(number : Int) {

            self.number = number

        }

        

        weak var topic : Module?

        

        deinit {

             print("子模块 topic 数为 \(number)") // 弱引用, 会被调用

        }

    }


    // (10)无主引用实例

    class StudentPeter {

        let name : String

        

        var section : MarkPeter?

        

        

        init(name: String) {

            self.name = name

        }

        

        deinit {

            print("析构函数:学生姓名\(name)") // 无主引用, 会被调用

        }

        

    }


    class MarkPeter {

        let marks : Int

        

        unowned let stname: StudentPeter

        

        init(marks: Int, stname: StudentPeter) {

            self.marks = marks

            self.stname = stname

        }

        

        deinit {

            print("析构函数:学生的分数:  \(marks)") // 无主引用, 会被调用

        }

        

    }


    // (11)闭包引起的循环强引用 实例

    class HTMLElement {

        let name : String

        let text : String?

        

        lazy var asHTML: () -> String = {  // 闭包在其闭包体内使用了self(引用了self.nameself.text

            if let text = self.text {      // 因此闭包捕获了self,这意味着闭包又反过来持有了HTMLElement实例的强引用

                

                return "<\(self.name)>\(text)<\(self.name)>"

                

            } else {

                

                return "<\(self.name)>"

            }

        }

        

        

        lazy var asasHTML: () -> String = {

            [unowned self] in           // 无主引用是正确的解决循环强引用的方法

            if let text = self.text {

                return "<\(self.name)>\(text)</\(self.name)>"

            } else {

                return "<\(self.name) />"

            }

        }

        

        

        init(name: String, text: String?) {

            self.name = name

            self.text = text

        }

        

        deinit {

            print("\(name) is being deinitalized")

        }

    }



    // (12)扩展

    extension Int//a.下面的例子向 Int 类型添加了 4个计算型实例属性并扩展其功能

        

        var add: Int {

            return self + 100

        }

        var sub: Int {

            return self - 10

        }

        var mul: Int {

            return self * 10

        }

        var div: Int {

            return self / 5

        }

    }



    struct sum {

        var num1 = 100, num2 = 200

    }


    struct diff {

        var no1 = 200, no2 = 100

    }


    struct mult {

        var a = sum()

        var b = diff()

    }


    extension mult// 构造器扩展

        init(x: sum, y:diff) {

            _ = x.num1 + x.num2

            _ = y.no1 + y.no2

        }

    }


    extension Int { // 下面的例子向Int类型添加一个名为 topics 的新实例方法

        func topics(summation: () -> ()) {

            for _ in 0..<self {

                summation()

            }

        }

    }

    // 下面的例子向 Swift Double 类型添加了一个新的名为 square 的修改方法,来实现一个原始值的平方计算:   mutating

    extension Double {

        mutating func square() {

            let PI = 3.1415

            self = PI * self * self

        }

    }

    // 以下例子向 Swift 内建类型Int添加了一个整型下标。该下标[n]返回十进制数字    subscript

    extension Int {

        subscript(var muttable: Int) -> Int {

            var no1 = 1

            while muttable > 0 {

                no1 += 10

                muttable -= 1

            }

            

            return (self / no1) % 10

        }

    }


    // (13)协议

    protocol classa {

        var marks : Int { set get }

        var result : Bool { get }

        

        func attendance() -> String

        func marksseucred() -> String

    }


    protocol calssb: classa {

        var present : Bool { get set }

        var subject : String { get set }

        var stname : String {get set }

    }


    class classc: calssb {

        var marks = 96

        let result = true

        var present = false

        var subject = "Swift 协议"

        var stname = "Protocol"

        

        func attendance() -> String {

            return "The \(stname) has secured 99% attendance"

        }

        

        func marksseucred() -> String {

            return  "\(stname) has scored \(marks)"

        }

    }

    // Mutating 方法的规定

    protocol daysofaweek {

        mutating func show()

    }


    enum days: daysofaweek {

        case sun, mon, tue, wed, thurs, fri, sat

        mutating func show() {

            switch self {

            case sun:

                self = sun

                print("Sunday")


            case mon:

                self = mon

                print("Monday")

            

            default:

                print("no such day !")

            }

        }

    }

    //对构造器的规定

    protocol tcpprotocol {

        init(aprot: Int)

    }


    class tcpClass: tcpprotocol // required, 你可以在遵循该协议的类中实现构造器,并指定其为类的指定构造器或者便利构造器

        required init(aprot: Int) {

            

        }

    }


    class mClass {

        var no1 : Int // 局部变量

        init(aprot: Int) {

            self.no1 = aprot // 初始化

        }

    }


    class sClass: mClass, tcpprotocol {

        var no2 : Int

        init(no1: Int, no2: Int) {

            self.no2 = no2

            super.init(aprot: no1)

        }

        

        // 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override"

        required override convenience init(aprot: Int) {

            self.init(no1:aprot, no2:0)

        }

    }

    // 协议类型

    protocol Generator {

        associatedtype memebers

        func next() -> memebers?

    }


    // 在扩展中添加协议成员

    protocol AgeClassficationProtocol {

        var age: Int { get }

        func agetype() -> String

    }


    class Personss {

        let firstname : String

        let lastname : String

        var age : Int

        

        init(firstname: String, lastname: String) {

            self.firstname = firstname

            self.lastname = lastname

            self.age = 10

        }

    }


    extension Personss: AgeClassficationProtocol {

        func fullname() -> String {

            var c : String

            c = firstname + " " + lastname

            return c

        }

        

        func agetype() -> String {

            switch age {

            

            case 0...2:

                return "Baby"

            case 2...12:

                return "Child"

            case 13...19:

                return "Teenager"

            case let x where x > 65:

                return "Elderly"

                

            default:

                return "Normal"

            }

        }

    }

    // 协议的继承

    protocol sAgeClassProtocol: AgeClassficationProtocol {

        

    }


    // 类专属协议

    protocol specalClassProtocol: class, AgeClassficationProtocol {

        

    }


    // 协议合成

    protocol Stname {

        var name : String { get }

    }


    protocol Stage {

        var age : Int { get }

    }


    struct PerSonsss:Stname, Stage {

        var name: String

        var age: Int

    }


    // 检验协议的一致性 : is  as?  as

    protocol HasArea {

        var area: Double { get }

    }


    class Circle: HasArea { // 定义了Circle类,都遵循了HasArea协议

        let PI  = 3.1415

        let radius : Double

        var area: Double { return PI * radius * radius }

        

        init(radius: Double) {

            self.radius = radius

        }

    }


    class Country: HasArea { // 定义了Country类,都遵循了HasArea协议

        var area: Double

        init(area: Double) {

            self.area = area

        }

    }


    class Animal { // Animal是一个没有实现HasArea协议的类

        var legs : Int

        init(legs: Int) {

            self.legs = legs

        }

    }


    // (14)泛型

    struct TOS<T> {

        var items = [T]()

        mutating func push(item: T) {

            items.append(item)

        }


        mutating func pop() -> T {

            return items.removeLast()

        }

    }


    extension TOS { // 扩展泛型类型

        var first : T? {

            return items.isEmpty ? nil : items[items.count - 1]

        }

        

        

    }


    // 关联类型实例

    protocol Container {

        // 定义了一个ItemType关联类型

        associatedtype ItemType

        mutating func append(item: ItemType)

        var count : Int { get }

        subscript(i: Int) -> ItemType { get }

        

    }


    struct TOSCon<T>: Container { // 遵循Container协议的泛型 TOSCon 类型

        var items = [T]()

        mutating func push(item: T) {

            items.append(item)

        }

        

        mutating func pop() -> T {

            return items.removeLast()

        }

        

        mutating func append(item: T) {

            self.push(item)

        }

        

        var count: Int {

            return items.count

        }

        

        subscript(i: Int) -> T {

            return items[i]

        }

        

    }


    // 下面的例子定义了一个名为allItemsMatch的泛型函数,用来检查两个Container实例是否包含相同顺序的相同元素。

    // 如果所有的元素能够匹配,那么返回一个为trueBoolean值,反之则为false

    struct Stack<T>: Container {

        var items = [T]()

        mutating func push(item: T) {

            items.append(item)

        }

        

        mutating func pop() ->T {

            return items.removeLast()

        }

        

        mutating func append(item: T) {

            self.push(item)

        }

        

        var count: Int {

            return items.count

        }

        

        subscript(i: Int) -> T {

            return items[i]

        }

    }


    // 访问权限

    // 枚举类型访问权限

    public enum StudentAll { //枚举 StudentAll 被明确的申明为 public 级别,那么它的成员 NameMark 的访问级别同样也是 public

        case Name(String)

        case Mark(Int, Int, Int)

    }


    // 子类访问权限: 子类访问级别不得高于父类访问级别

    public class superClassss {

        private func show() {

            print("父类")

        }

    }

    // 访问级别不能低于超类 internal > public

    internal class ssClassss: superClassss {

        override internal func show() {

            print("子类")

        }

    }


    // Getter Setter 访问权限

    class samplegm {

        private var counter: Int = 0 {

            willSet(newTotal) {

                print("计数器: \(newTotal)")

            }

            

            didSet {

                if counter > oldValue {

                    print("新增加数量: \(counter - oldValue)")

                }

            }

        }

    }


    // 构造器和默认构造器访问权限

    class classAa {

        required init() {

            var a = 10

            print(a)

            

        }

    }


    class clssAb: classAa {

        required init() {

            var b = 30

            print(b)

        }

    }












































    展开全文
  • swift之闭包的使用

    2019-01-03 15:02:24
    =============================...闭包 = { (行) -&gt; 返回值 in  // 代码实现 } ==================== //调用闭包  func clousre() {  ac()//无参数无返回值  a()//无参数无返回值的闭包的简写...

     

    =============================闭包的通用形式===================

    闭包 = { (行参) -> 返回值 in

        // 代码实现

    }

    ====================

    //调用闭包

     func clousre() {

            ac()//无参数无返回值

            a()//无参数无返回值的闭包的简写

            

            b(1)//有参数无返回值的闭包

            let cs=c(1)//有有参数有返回值

            print(cs)

            

        }

     

    *************

     

     

     

     //无参数无返回值----最简单的闭包

            let a={

              

               print("3")

            }

            a()

     

     

     

    //有参数无返回值-----省略了返回值的闭包

            let a={

                (x:Int) in

               print(x)

            }

            a(4)

     

    //2、定义一个最简单的闭包,() -> () 没有参数,没有返回值

     

     

     

    let ac = {()->() in

            print("无参数无返回值的")

        }

        let a={

            print("无参数无返回值的闭包的简写")

        }

     

     

     

    //3、定义一个带参数的闭包

    //通过“in”关键字,对闭包的定义和实现进行分割,没有参数没有返回值可以省略in

    // { (形参列表)   返回值类型  ->() in  实现代码}

     

    let b={(x:Int)->()in

     

            print("有参数\(x)无返回值")

        }

     

     

    //4、定义一个带参数,有返回值的闭包

     

    let c={(x:Int)->Intin

            return x+10

        }

     

     

    //注:在OC中{}用来分隔作用域的,而在swift中,表示一个闭包  

     

    //5.尾随闭包:如果一个函数的最后一个参数是闭包,则函数的参数可以提前结束,最后一个参数直接使用{}包装闭包的代码

     

     let per = LYBHomeVC()

        

        //******1、正常调用对象的函数---闭包作为函数参数

        per.loadData(callBack: { () -> () in

        print("闭包作为函数参数")

        })

        

        //******2、尾随闭包的改进:函数的参数可以提前结束,后面直接跟上一个闭包包装代码

        per.loadData() { () -> () in

        print("闭包作为函数参数提前结束参数")

        }

        

        //*****3、尾随闭包简写

        per.loadData {

        print("闭包作为函数参数简写")

        }

     

     

     

    ===============闭包的循环引用的解决方法

     

    //如果记录了闭包属性,然后在闭包中又使用了self,则产生了循环引用

    //解决闭包中的循环引用

    //方法一:

    //weak只能修饰var,不能修饰let因为如果weak的指针在运行时会被修改,会自动设置为nil

    weak var weakself =self

    loadData {

        //!:强制解包,必须有值,如果解包的值为nil,则崩溃

        //?:可选解包,如果解包为nil,则不会执行后面的内容

        print(weakself?.view ?? "")

    }

     

    //方法二:推荐

    //[weak self]表示闭包中的self都是弱引用

    loadData { [weak self] in

        print(self?.view ?? "")

    }

     

    //方法三:类似OC中的unsafe、_unretained,常用

    //[unowned self]表示闭包中的self为assign,如果self被释放,则指针地址不会被释放,容易导致出现野指针

    loadData { [unowned self] in

        print(self.view)

    }

    =============闭包作为属性===========

    属性:
    var strBlock : ((_ str1 : String, _ str2 : String) -> Void)?
    实现闭包:
     let vcOne = TestOne()
            // 实现闭包 处理回调
            vcOne.strBlock = {(str1 : String, str2 : String) -> Void in
                print(str1 + str2)
            }
    
    调用:
     strBlock?("hello", "world")
    
    
    
    
    //有参数无返回值:
     var  scrollClickBlock:(Int)->()={ (Int)in return }
    
    调用:let lunbo:LYBHomelunboview=LYBHomelunboview.init(frame: CGRect(x: 0, y: 0, width:Int(WIDTH) , height:LUNBOHEIGHT))
            lunbo.scrollClickBlock={
                [weak self]//解决循环引用
                (index)  in
                //传过来的tag,是从2开始
                switch index {
                case 0:break
                case 1: break
                case 2:
                    print("\(index)")
                    break
                case 3:
                    
                    break
                default: break
                    
                }
                
                return 
            }
    
    //有参数有返回值
     var  loginBlock:(NSInteger)->(NSInteger)?={ (NSInteger)in return 0}
    
    调用:     let mineTabHeaderview:LYBMyHeaderview=LYBMyHeaderview.init(frame:CGRect.init(x: 0, y: 0, width: WIDTH, height: 200))
    //  weak var weakSelf = self//解决循环引用
            mineTabHeaderview.loginBlock={
                [weak self]//解决循环引用
              (index)  in
               
                switch index {
                case 0:
                    let loginvc: LYBLoginVC=LYBLoginVC()
            
                         self?.present(loginvc, animated: true, completion: nil)
                    
                   
                default: break
                    
                }
                
                return 0
            }

    ========闭包作为函数参数====

    func handler(_ a: Int, _ b: Int,operation:(Int,Int)->Int) ->Int {
        let res = operation(a,b)
        return res
    }
    
    let multipyClosure = { //实现一个闭包
        (a:Int,b:Int) in
        a * b
    }
    
    handler(2, 3, operation: multipyClosure) //将闭包作为参数传递
    
    

    *************闭包的不同应用场景:

    http://www.cocoachina.com/ios/20161225/18412.html

    https://www.cnblogs.com/Abnerzj/p/6094346.html

    闭包作为参数https://blog.csdn.net/shifang07/article/details/76293244

    函数和闭包作为函数参数的区别:http://www.cnblogs.com/rayshen/p/5039735.html

     

    展开全文
  • 今天在网上看到一个比较简单好用的日历组件,重要的是它是基于swift的。 官方地址在这里:CVCalendar 其实官方开发人员在产品的首页上已经把如何使用写得非常清楚了。而我在使用过程中,也操考了一个国内的博主: ...

    今天在网上看到一个比较简单好用的日历组件,重要的是它是基于swift的。

    官方地址在这里:CVCalendar

    其实官方开发人员在产品的首页上已经把如何使用写得非常清楚了。而我在使用过程中,也参考了一个国内的博主:

    http://blog.csdn.net/mo_xiao_mo/article/details/53991496

    这位博主也整理得十分清楚。

    一、准备工作

    1、首先从官方团队的GitHub首页上将项目下载下来:


    2、将工程文件CVCalendar.xcodeproj直接拖动到工程当中去:


    3、在xcode中的左侧项目结构目录中,选中你的工程名称,在中部切换到General视图,然后找到“Embeded Binaries”项,在该项中添加“CVCalendar.framework”:


    二、代码实现

    1、首先导入组件:
    import CVCalendar
    2、继承两个代理:
     - CVCalendarDelegate
     - CVCalendarMenuViewDelegate
    class CVCalendarViewController: UIViewController{
        //...
    }
    
    extension CVCalendarViewController: CVCalendarViewDelegate,CVCalendarMenuViewDelegate {
        //...
    }
    3、定义两个UIView,分别用来显示日历上方的菜单栏(用以显示周一到周日)以及日历本身:
    var viewCalendarMenu: CVCalendarMenuView!
        
    var viewCalendar: CVCalendarView!
    4、初始化这两个UIView:
    /*
     *  初始化日历菜单
     */
    self.viewCalendarMenu = CVCalendarMenuView(frame: CGRect(x:0,y:60, width:300, height:135))
        
    /*
     *  初始化日历
     */
    self.viewCalendar = CVCalendarView(frame: CGRect(x:0, y:143, width:300, height:450))
    
    5、为这两个UIView注册代理:
    /*
     *  为日历菜单注册代理
     */
    self.viewCalendarMenu.menuViewDelegate = self
            
    /*
     *  为日历注册代理
     */
    self.viewCalendar.calendarDelegate = self
    6、将日历组件放置到界面上:
    /*
     *  将日历组件放在界面上
     */
    self.view.addSubview(self.viewCalendarMenu)
    self.view.addSubview(self.viewCalendar)
    7、最关键的一步,你需要重写以下这个方法,用来刷新日历组件,否则日历无法显示在界面上:
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.viewCalendarMenu.commitMenuViewUpdate()
        self.viewCalendar.commitCalendarViewUpdate()
    }

    到此为止,其实已经能够运行程序并且看到日历的样子了:


    我把上面这些步骤封装在了一个方法中,这样只需要在viewDidLoad中调用这个方法就可以了:
    var viewCalendarMenu: CVCalendarMenuView!
        
    var viewCalendar: CVCalendarView!
        
    override func viewDidLoad() {
        super.viewDidLoad()
    
        /*
         *  初始化日历组件
         */
        self.initCalendar()
    }
    
    /**
     *  初始化日历组件
     */
    func initCalendar()->Void{
        /*
         *  在页面顶端显示当前的日期
         */
        let currentCalendar:Calendar = Calendar.init(identifier: .gregorian)
        self.title = CVDate(date: Date(), calendar: currentCalendar).globalDescription
        
        /*
         *  初始化日历菜单
         */
        self.viewCalendarMenu = CVCalendarMenuView(frame: CGRect(x:0,y:60, width:300, height:135))
        
        /*
         *  初始化日历
         */
        self.viewCalendar = CVCalendarView(frame: CGRect(x:0, y:143, width:300, height:450))
            
        /*
         *  为日历菜单注册代理
         */
        self.viewCalendarMenu.menuViewDelegate = self
            
        /*
         *  为日历注册代理
         */
        self.viewCalendar.calendarDelegate = self
            
        /*
         *  将日历组件放在界面上
         */
        self.view.addSubview(self.viewCalendarMenu)
        self.view.addSubview(self.viewCalendar)
    }

    三、扩展

    其实这个第三方组件还提供了一些比较方便好用的高级扩展,关于这一点也可以查看官方团队给出的说明:
    点击这里查看官方高阶api
    1、设置一周的第一天
    func firstWeekday() -> Weekday {
        return .Sunday
    }
    2、跳转月份
    在这个扩展例子中,官方写了两个方法
    第一个方法用来直接返回当月:
    @IBAction func todayMonthView() {
        self.calendarView.toggleCurrentDayView()
    }
    第二个方法用来直接跳到一个指定月份,注意入参并不是直接表示月份数,而是表示希望跳转到的月份与当月之间相差多少个月:
    func toggleMonthViewWithMonthOffset(offset: Int) {
        let calendar = NSCalendar.currentCalendar()
        let calendarManager = CVCalendarManager.sharedManager
        let components = calendarManager.componentsForDate(NSDate()) // from today
            
        components.month += offset
        components.day = 1 // CVCalendar will select this day view
            
        let resultDate = calendar.dateFromComponents(components)!
            
        self.calendarView.toggleMonthViewWithDate(resultDate)
    }
    3、往前或往后一个月:
    self.calendarView.loadNextMonthView()
    self.calendarView.loadPreviousMonthView()
    4、显示不属于当前月份的日期:
    self.viewCalendar!.changeDaysOutShowingState(shouldShow: true) 
    5、动态切换日历的显示模式:
    切换为周历
    calendarView.changeMode(.WeekView)
    切换为月历
    calendarView.changeMode(.MonthView)

    而在上文所提到的那位国内博主的文章中,也整理了一些比较有用的扩展,因为他整理得非常好,所以就直接转过来:
    extension CVCalendarViewController: CVCalendarViewDelegate,CVCalendarMenuViewDelegate {
        //视图模式
        func presentationMode() -> CalendarMode {
            //使用月视图
            return .monthView
        }
        
        //每周的第一天
        func firstWeekday() -> Weekday {
            //从星期一开始
            return .monday
        }
        
        func presentedDateUpdated(_ date: CVDate) {
            //导航栏显示当前日历的年月
            self.title = date.globalDescription
        }
        
        //每个日期上面是否添加横线(连在一起就形成每行的分隔线)
        func topMarker(shouldDisplayOnDayView dayView: CVCalendarDayView) -> Bool {
            return true
        }
        
        //切换月的时候日历是否自动选择某一天(本月为今天,其它月为第一天)
        func shouldAutoSelectDayOnMonthChange() -> Bool {
            return false
        }
        
        //日期选择响应
        func didSelectDayView(_ dayView: CVCalendarDayView, animationDidFinish: Bool) {
            //获取日期
            let date = dayView.date.convertedDate()!
            // 创建一个日期格式器
            let dformatter = DateFormatter()
            dformatter.dateFormat = "yyyy年MM月dd日"
            let message = "当前选择的日期是:\(dformatter.string(from: date))"
            //将选择的日期弹出显示
            let alertController = UIAlertController(title: "", message: message,preferredStyle: .alert)
            let okAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
            alertController.addAction(okAction)
            self.present(alertController, animated: true, completion: nil)
        }
    }

    展开全文
  • 一、设置系统权限 这一点非常重要,找到工程内的info.plist文件,在其中添加以下项: Privacy - Photo Library Usage Description为你添加的项设置Type为String,然后在Value一列中输入一句话,可以任意输入,这句...

    一、设置系统权限

    这一点非常重要,找到工程内的info.plist文件,在其中添加以下项:
    Privacy - Photo Library Usage Description
    为你添加的项设置Type为String,然后在Value一列中输入一句话,可以任意输入,这句话旨在提醒用户我们需要获得使用摄像头的权限:

    二、实现/继承代理

    调取系统相册需要用到以下两个系统代理:
    UIImagePickerControllerDelegate
    UINavigationControllerDelegate
    所以我们的ViewController需要实现这两个代理:
    import UIKit
    
    class DemoTakePhotoViewController: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
    //...
    }

    三、编写方法,调取系统相册

    调取摄像头其实就是呼出一个系统已定义的ViewController:
    UIImagePickerController
    具体使用该ViewController的方式如下:
    let photoPickerViewController:UIImagePickerController = UIImagePickerController()
    photoPickerViewController.sourceType = UIImagePickerControllerSourceType.photoLibrary
    photoPickerViewController.delegate = self
    self.present(photoPickerViewController, animated: true, completion: nil)

    注意上面代码中,在第二行等号的右边所出现的以下代码:
    UIImagePickerControllerSourceType.photoLibrary
    就是这句代码,指定了UIImagePickerController要打开的是系统相册,我们可以查看一下UIImagePickerControllerSourceType类的源代码,发现它本身是一个枚举:
    public enum UIImagePickerControllerSourceType : Int {
     
        case photoLibrary
    
        case camera
    
        case savedPhotosAlbum
    }
    这个枚举非常简单易懂:
    photoLibrary:系统图库
    camera:系统摄像头
    savedPhotosAlbum:相册
    也就是说我们可以通过设置photoPickerViewController的sourceType为上述三项中的一项,来决定调用哪个系统功能

    稍微进一步查看一下源代码,我们发现还有其它非常多的枚举量:
    public enum UIImagePickerControllerSourceType : Int {
    
        
        case photoLibrary
    
        case camera
    
        case savedPhotosAlbum
    }
    
    public enum UIImagePickerControllerQualityType : Int {
    
        
        case typeHigh // highest quality
    
        case typeMedium // medium quality, suitable for transmission via Wi-Fi 
    
        case typeLow // lowest quality, suitable for tranmission via cellular network
    
        @available(iOS 4.0, *)
        case type640x480 // VGA quality
    
        @available(iOS 5.0, *)
        case typeIFrame1280x720
    
        @available(iOS 5.0, *)
        case typeIFrame960x540
    }
    
    public enum UIImagePickerControllerCameraCaptureMode : Int {
    
        
        case photo
    
        case video
    }
    
    public enum UIImagePickerControllerCameraDevice : Int {
    
        
        case rear
    
        case front
    }
    
    public enum UIImagePickerControllerCameraFlashMode : Int {
    
        
        case off
    
        case auto
    
        case on
    }
    看懂这些枚举量的用途不需要太好的英文水平,除了在本例中用到的UIImagePickerControllerSourceType外,我在这里将其它枚举量简单做个说明:

    UIImagePickerControllerQualityType:成像质量

    UIImagePickerControllerCameraCaptureMode:拍照或者录像

    UIImagePickerControllerCameraDevice:选择前置摄像头或是后置摄像头

    UIImagePickerControllerCameraFlashMode:闪光灯模式


    不再展开了,继续回来。我将调用摄像头拍照的代码封装成了一个方法,便于绑定到触发事件上:
    /**
     *  当用户点击界面上的相册按钮时,会打开系统相册,从而让用户选择照片
     */
    @IBAction func pickPhotoFromAlbum(_ sender: Any) {
        /*
         *  用来打开系统相册的view controller
         */
        let photoPickerViewController:UIImagePickerController = UIImagePickerController()
        photoPickerViewController.sourceType = UIImagePickerControllerSourceType.photoLibrary
        photoPickerViewController.delegate = self
        self.present(photoPickerViewController, animated: true, completion: nil)
    
    }

    四、编写方法,获取从相册选择的图片

    要获取从相册所拍选择的图片,我们主要需要重载以下方法:
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    //...
    }
    注意这个方法入参列表中的第二个参数“didFinishPickingMediaWithInfo info:[String : Any]”,选择的结果就会被保存在这个参数里面,我们可以通过以下方法来获取:
    guard var selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
        fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
    }
    这样一来,从相册选择的照片就成为了一个UIImage对象。
    下面贴出完整的方法:
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        guard var selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
            fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
        }
    
        picker.dismiss(animated: true, completion: nil)
    }
    拿到了UIImage对象后,我们就可以做自己需要的操作了,比如将图片显示在界面上,或是上传到服务器

    五、编写方法,取消选择

    以下方法为我们提供了退出相册的途径:
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }

    小结

    调取相册的各项功能都用到了Swift提供的代理(delegate)机制,它的最大的好处在于,在上述各步骤中,我们只有在调取相册的时候需要手动触发,其它方法全部都由代理自动调用,我们只要实现这些方法就可以了。
    展开全文
  • 一、设置系统权限 这一点非常重要,找到工程内的info.plist文件,在其中添加以下项: Privacy - Camera Usage Description为你添加的项设置Type为String,然后在Value一列中输入一句话,可以任意输入,这句话旨在...
  • Swift 闭包的使用

    2017-07-07 17:23:00
    在二级页面创建闭包class DetailViewController: UIViewController {// 定义闭包 typealias callBlock = (_ index:Int)->() // 无参数闭包的定义 typealias otherBlock = ()->() // 设置闭包属性 ...
  • swift3.0变化

    2016-09-26 15:08:44
    写在前面的废话:swift3.0改变了很多东西,以前的项目升级到xcode8后,报了好多错误,实在是无语。不过当了解了swift3.0新的特性后,还是抱有很大的期待
  • 初始化是类,结构体和枚举类型实例化的准备阶段。这个阶段设置这个实例存储的属性的初始化...和Objective-C不一样的是,Swift的构造器没有返回值。它们主要充当的角色是确保这个实例在使用之前能正确的初始化。 ...
  • 用来记录学习Swift中,与其他语法(java、kotlin)不同的难点和易忘点总结。 1.空合并运算符 var q:Int?=8 var value:Int value = q ?? 0 如果q为nil,value = 0,否则,value = q。相当于 var q:Int?=8 var value:...
  • swift笔记

    2020-02-04 10:11:11
    Swift5.1 https://docs.swift.org/swift-book/LanguageGuide/Subscripts.html 1、swift没有隐式转化 Swift中没有隐式转化,不会将整形自动转成浮点型 let m = 32 let n = 3.14 let result = m + n 错误写法 ...
  • Swift3.0-基础知识点

    2017-01-08 21:00:52
    import UIKit class ViewController: UITabBarController {  enum DayssofaWeek {// 星期  case Sunday  case Monday  case TUESDAY  case WEDNESDAY
  • 初始化是类,结构体和枚举类型实例化的准备阶段。这个阶段设置这个实例存储的...和Objective-C不一样的是,Swift的构造器没有返回值。它们主要充当的角色是确保这个实例在使用之前能正确的初始化。   类实例...
  •  //提供给主控制器调用 参数:方向,是否移动过的Bool值为入的闭包  func queenMove(direction : MoveDirection , completion : (Bool) -> ()){  let changed = performMove(direction: di
  • 一、前言   现在web前端发展越来越快,为了追求应用的快速开发和迭代,许多产品都会选择混合开发,在手机端嵌入web页面,那么这就会导致一个问题,原生代码怎么和js交互?那么下边我们共同学习一下iOS和web是怎么...
  • swift(一)基础知识

    2020-04-29 19:18:30
    //命名可以用字母、数字、下划线,不能以数字开头,区分大小写(同oc) swift强类型语言,自动判断类型 /var 变量/ var varConstant = 2 var varx = 1, vary = 2, varz = 3 var varString: String = ...
  • 作者:樊亦凡juejin.im/post/5eb9faa26fb9a0437e0e9899轻松实战性理解Optional1.前言相信不少小伙伴已经被java的NPE(Null Point...
  • 另辟蹊径--极简Swifty路由 1. 前言 在组件化通信方案的设计之初,尽管我们是纯Swift的组件化,我也一直难逃窠臼的想用注册(无论是注册协议还是注册URL)的方式来解决问题,或者...iOS 组件化 —— 路由设计思路分析
1 2 3 4 5
收藏数 81
精华内容 32
关键字:

present带参 swift