4.0 demo swift_ios swift3.0 demo - CSDN
  • Bluetooth4.0Demo 蓝牙4.0简单使用demo
  • Swift4.0 简单项目demo

    2018-06-13 19:00:48
    swift4.0基于MVVM开发模式的简单demo1.Alamofire (swift版的AFNetworking)封装与使用2.ESPullToRefresh 上拉加载下拉刷新 简单使用3.Kingfisher(swift版的SDWebImage)使用4.SnapKit(swift版的Masonry)使用5....

    swift4.0基于MVVM开发模式的简单demo

    1.Alamofire (swift版的AFNetworking)封装与使用

    2.ESPullToRefresh 上拉加载下拉刷新 简单使用

    3.Kingfisher(swift版的SDWebImage)使用

    4.SnapKit(swift版的Masonry)使用

    5.SwiftyJSON(swift版本的JSONModel)使用

    6.代理和block的使用

    7.简单视频播放

    下载链接:https://pan.baidu.com/s/1RsJ_3Qxc1QqBRX1eP2b26A

    展开全文
  • key-path 通常是用在键值编码(KVC)与键值观察(KVO)上的,KVC、KVO 相关内容可以参考我之前写的这篇文章:Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)
  • //// ViewController.swift// 008-switch//// Created by 庄壮勇 on 2018/1/3.// Copyright © 2018年 Personal. All rights reserved.//import UIKitclass ViewController: UIViewController { override func ...

    //
    //  ViewController.swift
    //  008-switch
    //
    //  Created by 庄壮勇 on 2018/1/3.
    //  Copyright © 2018年 Personal. All rights reserved.
    //

    import UIKit

    class ViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()
            demo(num: "10")
        }

        /**
         1.switch 可以针对任意类型的值进行分支,不再局限在整数
         2.switch 一般不需要break
         3.switch 如果要多值。使用','
         4.所有的分支至少需要一条指令
         */
        func demo(num: String) {
            switch num {
            case "10","9":
                print("优")
            case "8":
                break;
            default:
                print("一般")
            }
        }
    }


    展开全文
  • //// ViewController.swift// 011-数组//// Created by 庄壮勇 on 2018/1/3.// Copyright © 2018年 Personal. All rights reserved.//import UIKitclass ViewController: UIViewController { override func ...

    //
    //  ViewController.swift
    //  011-数组
    //
    //  Created by 庄壮勇 on 2018/1/3.
    //  Copyright © 2018年 Personal. All rights reserved.
    //

    import UIKit

    class ViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()
            demo5()
        }
       
        // MARK: - 数组的合并
        func demo5() {
            var array:[Any] = ["张三","小芳","小羊"]
            let array2 = ["老刀","1","2",180] as [Any]
           
            // 将array2 的内容合并到 array
            // ***注意: 要合并数组的类型必须一致
            array += array2
           
            print(array)
        }
       
        // MARK: - 数组的容量
        func demo4() {
            // 定义一个数组,指定类型是 存放Int 的数组,但是没有初始化
    //        var array:[Int]
    //        // 给数组进行初始化
    //        array = [Int]()
           
            // 以上两句代码可以合并成一句
            var array = [Int]()
            print("初始容量 \(array.capacity)")

            for i in 0..<8 {
                array.append(i)
                print("\(array) 容量 \(array.capacity)")
            }
           
        }

        // MARK: - 数组的增/删/改
        func demo3() {
            // OC 中数组分可变NSMutableArray(var) 不可变 NSArray(let)
            var array = ["张三","小芳","小羊"]

            // 追加元素
            array.append("老王")
            print(array)
           
            // 修改,通过下标定位
            array[0] = "小王"
            print(array)
           
            // 数组越界 - Index out of range
            //array[5] = "XXXX"
            //print(array)
            // 删除
            array.remove(at: 3)
            print(array)
           
            // 删除全部,并且保留空间
            array.removeAll(keepingCapacity: true)
            print("\(array) \(array.capacity)")
        }
       
        // MARK: - 数组的遍历
        func demo2() {
            let array = ["张三","小芳","小羊"]
           
            // 1.按照下标遍历
            print("--- 按照下标遍历")
            for i in 0..<array.count {
                print(array[i])
            }

            // 2.for in 遍历元素
            print("--- 按照下标遍历")
            for s in array {
                print(s)
            }
           
            // 3. enum block 遍历, 同时遍历下标和内容
            print("--- 同时遍历下标和内容")
            // 元组
            for e in array.enumerated() {
                print("\(e.offset) \(e.element)")
            }
           
            // 4. 遍历下标和内容2
            print("--- 遍历下标和内容2")
            // n 就是索引下标
            // s 就是[String] 数组 n 对应的 String 元素
            // 其中 n / s 的名字可以随便写
            for (n,s) in array.enumerated() {
                print("\(n) \(s)")
            }

            // 5. 反序遍历
            print("--- 反序遍历")
            for s in array.reversed() {
                print(s)
            }
           
            // 6. 错误的反序索引&内容
            print("--- 错误反序索引&内容")
            for (n,s) in array.reversed().enumerated() {
                print("\(n) \(s)")
            }
            // 7. 正确的反序
            print("--- 正确反序索引&内容")
            // 先枚举,再反序
            for (n,s) in array.enumerated().reversed() {
                print("\(n) \(s)")
            }
        }
       
        // MARK: - 数组的定义
        func demo1() {
           
            // OC 使用[] 定义数组,Swift一样,但是没有'@'
            // 自动推导的结果[String] -> 表示数组中存放的都是String
            // 跟OC 中的数组指定泛型类似
            let array = ["张三","小芳","小羊"]
           
            print(array)
           
            // [Int] -> 表示存放的都是Int
            // Swift 中基本数据类型不需要包装!
            let array2 = [1,2,3,4,5]
            print(array2)
           
            // CG结构体
            let p = CGPoint(x: 10, y: 300)
            // [CGPoint]
            let array3 = [p]
            print(array3)
           
            // 混合数组: 开发中几乎不用,因为数组是靠下标索引
            // 如果数组中的类型不一致,自动推导的结果[NSObject]
            // 在Swift 中还有一种类型[AnyObject] -> 任意对象
            // 在Swift 中一个类可以没有任何‘父类’
            NSValue(cgPoint: p)
            let array4 = ["张三",1,NSValue(cgPoint: p)] as [Any]
            print(array4)
        }
    }


    展开全文
  • key-path 通常是用在键值编码(KVC)与键值观察(KVO)上的,KVC、KVO 相关内容可以参考我之前写的这篇文章:Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍) 1.Swift 3 之前使用的是 String 类型的 key-...

    一、Key Paths 新语法

    key-path 通常是用在键值编码(KVC)与键值观察(KVO)上的,KVC、KVO 相关内容可以参考我之前写的这篇文章:Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)

    1.Swift 3 之前使用的是 String 类型的 key-Path

    //用户类
    class User: NSObject{
        @objc var name:String = ""  //姓名
        @objc var age:Int = 0  //年龄
    }
     
    //创建一个User实例对象
    let user1 = User()
    user1.name = "hangge"
    user1.age = 100
     
    //使用KVC取值
    let name = user1.value(forKey: "name")
    print(name)
     
    //使用KVC赋值
    user1.setValue("hangge.com", forKey: "name")
    复制代码

    具体显示如下:

    2.到了 Swift 3 新增了 #keyPath() 写法 使用 #keyPath() 写法,可以避免我们因为拼写错误而引发问题。

    //用户类
    class User: NSObject{
        @objc var name:String = ""  //姓名
        @objc var age:Int = 0  //年龄
    }
     
    //创建一个User实例对象
    let user1 = User()
    user1.name = "hangge"
    user1.age = 100
     
    //使用KVC取值
    let name = user1.value(forKeyPath: #keyPath(User.name))
    print(name)
     
    //使用KVC赋值
    user1.setValue("hangge.com", forKeyPath: #keyPath(User.name))
    复制代码

    3.Swift 4 中直接用 \ 作为开头创建 KeyPath 新的方式不仅使用更加简单,而且有如下优点:

    • 类型可以定义为 class、struct
    • 定义类型时无需加上 @objc 等关键字
    • 性能更好
    • 类型安全和类型推断,例如:user1.value(forKeyPath: #keyPath(User.name)) 返回的类型是 Any,user1[keyPath: \User.name] 直接返回 String 类型
    • 可以在所有值类型上使用 (1)比如上面的样例在 Swift4 中可以这么写:
    //用户类
    class User: NSObject{
        var name:String = ""  //姓名
        var age:Int = 0  //年龄
    }
     
    //创建一个User实例对象
    let user1 = User()
    user1.name = "hangge"
    user1.age = 100
     
    //使用KVC取值
    let name = user1[keyPath: \User.name]
    print(name)
     
    //使用KVC赋值
    user1[keyPath: \User.name] = "hangge.com"
    复制代码

    (2)keyPath 定义在外面也是可以的:

    let keyPath = \User.name
     
    let name = user1[keyPath: keyPath]
    print(name)
     
    user1[keyPath: keyPath] = "hangge.com"
    复制代码

    (3)可以使用 appending 方法向已定义的 Key Path 基础上填加新的 Key Path。

    let keyPath1 = \User.phone
    let keyPath2 = keyPath1.appending(path: \.number)
    复制代码

    二、类与协议的组合类型

    在 Swift 4 中,可以把类(Class)和协议(Protocol)用 & 组合在一起作为一个类型使用。

    使用样例1:

    protocol MyProtocol { }
     
    class View { }
     
    class ViewSubclass: View, MyProtocol { }
     
    class MyClass {
        var delegate: (View & MyProtocol)?
    }
     
    let myClass = MyClass()
    myClass.delegate = ViewSubclass() //这个编译正常
    myClass.delegate = View() //这个编译报错:
    复制代码

    具体错误信息如下:

    使用样例2:

    protocol Shakeable {
        func shake()
    }
     
    extension UIButton: Shakeable {
        func shake() {
            /* ... */
        }
    }
     
    extension UISlider: Shakeable {
        func shake() {
            /* ... */
        }
    }
     
    func shakeEm(controls: [UIControl & Shakeable]) {
        for control in controls where control.isEnabled {
            control.shake()
        }
    }
    复制代码

    三、下标支持泛型

    1.下标的返回类型支持泛型 有时候我们会写一些数据容器,Swift 支持通过下标来读写容器中的数据。但是如果容器类中的数据类型定义为泛型,过去下标语法就只能返回 Any,在取出值后需要用 as? 来转换类型。现在 Swift 4 定义下标也可以使用泛型了。

    struct GenericDictionary<Key: Hashable, Value> {
        private var data: [Key: Value]
         
        init(data: [Key: Value]) {
            self.data = data
        }
         
        subscript<T>(key: Key) -> T? {
            return data[key] as? T
        }
    }
     
    //字典类型: [String: Any]
    let earthData = GenericDictionary(data: ["name": "Earth", "population": 7500000000, "moons": 1])
     
    //自动转换类型,不需要在写 "as? String"
    let name: String? = earthData["name"]
    print(name)
     
    //自动转换类型,不需要在写 "as? Int"
    let population: Int? = earthData["population"]
    print(population)
    复制代码

    2.下标类型同样支持泛型

    extension GenericDictionary {
        subscript<Keys: Sequence>(keys: Keys) -> [Value] where Keys.Iterator.Element == Key {
            var values: [Value] = []
            for key in keys {
                if let value = data[key] {
                    values.append(value)
                }
            }
            return values
        }
    }
     
    // Array下标
    let nameAndMoons = earthData[["moons", "name"]]        // [1, "Earth"]
    // Set下标
    let nameAndMoons2 = earthData[Set(["moons", "name"])]  // [1, "Earth"]
    复制代码

    四、Codable 序列化

    如果要将一个对象持久化,需要把这个对象序列化。过去的做法是实现 NSCoding 协议,但实现 NSCoding 协议的代码写起来很繁琐,尤其是当属性非常多的时候。 Swift 4 中引入了 Codable 协议,可以大大减轻了我们的工作量。我们只需要让需要序列化的对象符合 Codable 协议即可,不用再写任何其他的代码。

    struct Language: Codable {
        var name: String
        var version: Int
    }
    复制代码

    1.Encode 操作 我们可以直接把符合了 Codable 协议的对象 encode 成 JSON 或者 PropertyList。

    let swift = Language(name: "Swift", version: 4)
     
    //encoded对象
    let encodedData = try JSONEncoder().encode(swift)
     
    //从encoded对象获取String
    let jsonString = String(data: encodedData, encoding: .utf8)
    print(jsonString)
    复制代码

    2.Decode 操作

    let decodedData = try JSONDecoder().decode(Language.self, from: encodedData)
    print(decodedData.name, decodedData.version)
    复制代码


    五、Subtring

    Swift 4 中有一个很大的变化就是 String 可以当做 Collection 来用,并不是因为 String 实现了 Collection 协议,而是 String 本身增加了很多 Collection 协议中的方法,使得 String 在使用时看上去就是个 Collection。

    let str = "hangge.com"
     
    print(str.prefix(5)) // "hangg"
    print(str.suffix(5)) // "e.com"
     
    print(str.dropFirst()) // "angge.com"
    print(str.dropLast()) // "hangge.co"
    复制代码

    比如上面的样例,我们使用一些 Collection 协议的方法对字符串进行截取,只不过它们的返回结果不是 String 类型,而是 Swift 4 新增的 Substring 类型。

    1.为何要引入 Substring? 既然我们想要的到的就是字符串,那么直接返回 String 就好了,为什么还要多此一举返回 Substring。原因只有一个:性能。具体可以参考下图: 当我们用一些 Collection 的方式得到 String 里的一部分时,创建的都是 Substring。Substring 与原 String 是共享一个 Storage。这意味我们在操作这个部分的时候,是不需要频繁的去创建内存,从而使得 Swift 4 的 String 相关操作可以获取比较高的性能。 而当我们显式地将 Substring 转成 String 的时候,才会 Copy 一份 String 到新的内存空间来,这时新的 String 和之前的 String 就没有关系了。

    2.使用 Substring 的注意事项 由于 Substring 与原 String 是共享存储空间的,只要我们使用了 Substring,原 String 就会存在内存空间中。只有 Substring 被释放以后,整个 String 才会被释放。 而且 Substring 类型无法直接赋值给需要 String 类型的地方,我们必须用 String() 包一层。当然这时系统就会通过复制创建出一个新的字符串对象,之后原字符串就会被释放。

    3.使用样例 这里对 String 进行扩展,新增一个 subString 方法。直接可以根据起始位置(Int 类型)和需要的长度(Int 类型),来截取出子字符串。

    extension String {
        //根据开始位置和长度截取字符串
        func subString(start:Int, length:Int = -1) -> String {
            var len = length
            if len == -1 {
                len = self.count - start
            }
            let st = self.index(startIndex, offsetBy:start)
            let en = self.index(st, offsetBy:len)
            return String(self[st ..< en])
        }
    }
    复制代码

    使用样例:

    let str1 = "欢迎访问hangge.com"
    let str2 = str1.subString(start: 4, length: 6)
    print("原字符串:\(str1)")
    print("截取出的字符串:\(str2)")
    复制代码

    运行结果如下:

    注意:这个方法最后我们会将 Substring 显式地转成 String 再返回。


    六、废除 swap 方法

    (1)过去我们会使用 swap(::) 来将两个变量的值进行交换:

    var a = 1
    var b = 2
    swap(&a, &b)
    print(a, b)
    复制代码

    (2)后面 swap() 方法将会被废弃,建议使用 tuple(元组)特性来实现值交换,也只需要一句话就能实现:

    var a = 1
    var b = 2
    (b, a) = (a, b)
    print(a, b)
    复制代码

    使用 tuple 方式的好处是,多个变量值也可以一起进行交换:

    var a = 1
    var b = 2
    var c = 3
    (a, b, c) = (b, c, a)
    print(a, b, c)
    复制代码

    (3)补充一下:现在数组增加了个 swapAt 方法可以实现两个元素的位置交换。

    var fruits = ["apple", "pear", "grape", "banana"]
    //交换元素位置(第2个和第3个元素位置进行交换)
    fruits.swapAt(1, 2)
    print(fruits)
    复制代码


    七、减少隐式 @objc 自动推断

    1.过去的情况(Swift 3) (1)在项目中如果想把 Swift 写的 API 暴露给 Objective-C 调用,需要增加 @objc。在 Swift 3 中,编译器会在很多地方为我们隐式的加上 @objc。 (2)比如当一个类继承于 NSObject,那么这个类的所有方法都会被隐式的加上 @objc。

    class MyClass: NSObject {
        func print() { } // 包含隐式的 @objc
        func show() { } // 包含隐式的 @objc
    }
    复制代码

    (3)但这样做很多并不需要暴露给 Objective-C 也被加上了 @objc。而大量 @objc 会导致二进制文件大小的增加。

    2.现在的情况(Swift 4) (1)在 Swift 4 中隐式 @objc 自动推断只会发生在下面这种必须要使用 @objc 的情况:

    • 覆盖父类的 Objective-C 方法
    • 符合一个 Objective-C 的协议

    (2)大多数地方必须手工显示地加上 @objc。

    class MyClass: NSObject {
        @objc func print() { } //显示的加上 @objc
        @objc func show() { } //显示的加上 @objc
    }
    复制代码

    (3)如果在类前加上 @objcMembers,那么它、它的子类、扩展里的方法都会隐式的加上 @objc。

    @objcMembers
    class MyClass: NSObject {
        func print() { } //包含隐式的 @objc
        func show() { } //包含隐式的 @objc
    }
     
    extension MyClass {
        func baz() { } //包含隐式的 @objc
    }
    复制代码

    (4)如果在扩展(extension)前加上 @objc,那么该扩展里的方法都会隐式的加上 @objc。

    class SwiftClass { }
     
    @objc extension SwiftClass {
        func foo() { } //包含隐式的 @objc
        func bar() { } //包含隐式的 @objc
    }
    复制代码

    (5)如果在扩展(extension)前加上 @nonobjc,那么该扩展里的方法都不会隐式的加上 @objc。

    @objcMembers
    class MyClass : NSObject {
        func wibble() { } //包含隐式的 @objc
    }
     
    @nonobjc extension MyClass {
        func wobble() { } //不会包含隐式的 @objc
    }
    复制代码

    ? 联系

    展开全文
  • Swift基础之PickerView选择器Demo
  • CmdBluetooth ... CmdBluetooth是一个针对于iOS的轻量级可扩展框架,Core内部将蓝牙周边抽象化,用户无需关注蓝牙内的操作细节与流程,仅需要你们自己的蓝牙协议,创造出自己的命令对象。 以往的蓝牙协议都是集中式...

    CmdBluetooth

    项目地址:https://github.com/ZeroFengLee/CmdBluetooth

    CmdBluetooth是一个针对于iOS的轻量级可扩展框架,Core内部将蓝牙周边抽象化,用户无需关注蓝牙内的操作细节与流程,仅需要你们自己的蓝牙协议,创造出自己的命令对象。

    以往的蓝牙协议都是集中式处理,出现逻辑复杂且混乱的现象,以至于扩展困难。CmdBluetooth将蓝牙的每条协议封装成不同命令对象,将复杂的逻辑分发下去,使得代码可读性增强,这也使得CmdBluetooth可以轻松的处理蓝牙协议的串行操作。

    我们团队当前开发使用的是OC版本,已经适用于5套以上不同的蓝牙协议。swift版本在完善中,如果你有好的建议,欢迎提交你的PR。

    开始使用

    • 将文件夹 "CmdBluetoothCore"导入到项目中
    • 参照文件夹 "CMDS" 根据具体的蓝牙协议封装命令
    • 参照 "ViewController"中使用框架

    框架结构

    CmdBluetoothCore

    • CentralManager
    • BaseParser
    • BaseCommand
    • D2PHosting
    • ParserSession
    • CmdConstants

    CMDS

    下面文件是使用者需要修改和扩展的,MyParser继承于BaseParser,SynTimeCmd继承于BaseCommand

    • MyParser
    • SynTimeCmd

    下面是每个类文件的角色解释

    Class name 解释 备注
    CentralManager 蓝牙中央的管理器,主要功能:蓝牙的搜索链接等操作  
    BaseParser 基础解析器类 创建自己的解析器时,务必继承此类,可以省掉很多基本操作
    BaseCommand 命令的基类,做了很多基础工作,如超时的定时器管理等 任何命令类都必须继承此类
    D2PHosting 在命令没开始/结束后,D2PHosting接管代理权,监听设备传向App的数据 这里可以处理设备的请求,如找手机等协议操作
    ParserSession 蓝牙解析器的抽象类  
    CmdConstants 常量管理类

    使用

    1. 拥有自己的解析器

      你只需要继承BaseParser类,并创建你的写入方法,请参照MyParser.swift

        /**
        define types for writing data to BLE device, like this
        */
        func writeDataWithResponse(data: NSData) {
    
            super.writeData(data, characterUuidStr: "fff6", withResponse: true)
        }
    
        func writeDataWithoutResponse(data: NSData) {
    
            super.writeData(data, characterUuidStr: "ff10", withResponse: false)
        }
    
        //......Many....many ^_^!
    1. 创建蓝牙命令 (假如你有20个蓝牙命令,那你需要20个这样的文件)

      请参照SynTimeCmd(时间同步命令),蓝牙主要是问答式的。

    2. 在命令开始前,一定要调用父类的start()方法去判断解析器是否可用。

        if !super.start() {
            //...
        }
    3. 在调用start()方法前,你可以设置超时时间(default:4)
        super.timeoutInterval = 5
    4. 在往蓝牙写数据时,记得把parserSession转成自己的解析器
        (self.parserSession! as! MyParser).writeDataWithResponse(self.testData())
    5. 复写父类的failure()方法,并调用super.failure()。检测超时失败的情况

        override func failure() {
      
            super.failure()
        }
    6. 在成功后调用父类的finish()刷新解析器的状态

        case 1:
            closureSuccess!()
            super.finish()
            break
    7. 使用CentralManager类来进行蓝牙的扫描链接等

      比较简单,请参照Demo.
      注意点:一定要传入自己的解析器对象,否则连接的周边无法被解析

      centerManager.parser = MyParser()
    8. 发送蓝牙协议

       SynTimeCmd().setCurrentTime({ () -> Void in
      
           print("suc")
       ) { () -> Void in
      
           print("fail")
       }
    展开全文
  • 经过我两天的鏖战,终于自己做出来一个swiftdemo,实现了在线注册,活体识别,给用swift的小伙伴们节省点时间,经过测试肯定好用,支持swift4.0。 [下载地址](https://download.csdn.net/download/qq_36841...
  • iOS 引用蓝牙4.0的小demo
  • //// ViewController.swift// 007-可选项的判断//// Created by 庄壮勇 on 2018/1/2.// Copyright © 2018年 Personal. All rights reserved.//import UIKitclass ViewController: UIViewController { override...
  • class ViewControllerI: UIViewController,UITableViewDelegate,UITableViewDataSource { var mytableView : UITableView? let testValue:NSString = "这是测试内容\n这是测试内容\n这是测试内容\n这是测试内容\n这...
  • Swift:我的第四个Demo

    2018-11-20 19:52:06
    这次Demo是关于UICollectionView的 // // ViewController.swift // UIKitPrograming // import UIKit class ViewController: UIViewController { // 定义一些不变量 let ScreenWidth = UIScreen.main.bounds....
  • Swift4.0 滑动新闻demo

    2018-07-06 14:37:02
    下载地址:https://pan.baidu.com/s/1H-hGziMznOHZCAKENCtShg
  • swift实现二维码的生成、扫描, swift实现iOS切换应用~ swift版本3 Xcode 7.3
  • swift实现App名,字符串资源,图片资源实现国际化(支持中文,英文,马来文,其它自己添加),Demo里面实现了语言切换功能!
  • iOS不同版本的自定义有所不同的,本文介绍iOS8下的自定义相机,所用语言为swift3+ // // TGCameraVCForiOS8.swift // TGPhotoPicker // // Created by targetcloud on 2017/8/11. // Copyright © 2017年 ...
  • 前面写了一部分关于Swift的语法学习,今天要学习的是Swift关于iOS中网络请求的AFNetwoking3.0的封装。Swift关于iOS中网络请求的AFNetwoking3.0的封装的流程有如下的几个步骤: 使用cocoaPods 下载AFNetwoking的库 ...
  • ios蓝牙使用demo

    2016-12-22 09:55:05
    简单粗暴上代码 步骤解释请看另一篇 ...demo下载 http://download.csdn.net/detail/swibyn/9717588#import "TableViewController.h" #import "CoreBluetooth/CoreBluetooth.h"#pra
  • swiftdemo

    2017-12-12 10:10:36
    写的练手的一个小 demo 用的是 swift4.0 不当之处 请多多指正数据都是网上扒的, 侵删效果图:传送门:https://github.com/ZJQian/Zealer
1 2 3 4 5 ... 20
收藏数 1,088
精华内容 435
关键字:

4.0 demo swift