└── Swifter.playground ├── Pages ├── assert.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── associated-object.xcplaygroundpage │ └── Contents.swift ├── associatedtype.xcplaygroundpage │ └── Contents.swift ├── autoclosure.xcplaygroundpage │ └── Contents.swift ├── class-cluster.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── closure-ambiguous.xcplaygroundpage │ └── Contents.swift ├── currying.xcplaygroundpage │ └── Contents.swift ├── default-param.xcplaygroundpage │ └── Contents.swift ├── delegate.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── documentation.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── enum-enumerate.xcplaygroundpage │ └── Contents.swift ├── enumerate.xcplaygroundpage │ └── Contents.swift ├── equal.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── error-handle.xcplaygroundpage │ └── Contents.swift ├── escaping.xcplaygroundpage │ └── Contents.swift ├── extension-generic.xcplaygroundpage │ └── Contents.swift ├── fatalError.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── final.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── func-dispatch.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── func-params.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── gcd-delay.xcplaygroundpage │ └── Contents.swift ├── general.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── hash.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── indirect-nested-enum.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── init-keyword.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── init-nil.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── init.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── instance-type.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── intropection.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── json.xcplaygroundpage │ ├── Contents.swift │ └── Sources │ │ └── SwiftyJSON.swift ├── kvo.xcplaygroundpage │ ├── Contents.swift │ └── Sources │ │ └── delay.swift ├── lazy.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── literal.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── local-scope.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── lock.xcplaygroundpage │ └── Contents.swift ├── log.xcplaygroundpage │ └── Contents.swift ├── math-number.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── memory-retain-cycle.xcplaygroundpage │ └── Contents.swift ├── multi-collection.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── multi-method.xcplaygroundpage │ └── Contents.swift ├── multiple-optional.xcplaygroundpage │ └── Contents.swift ├── nsnull.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── objc-dynamic.xcplaygroundpage │ └── Contents.swift ├── objc-protocol.xcplaygroundpage │ └── Contents.swift ├── operator.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── optional-chaining.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── optional-map.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── options.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── output-format.xcplaygroundpage │ └── Contents.swift ├── overflow.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── pattern-match.xcplaygroundpage │ └── Contents.swift ├── playground-delay.xcplaygroundpage │ └── Contents.swift ├── playground-liveview.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── pointer-memory.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── print.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── property-observer.xcplaygroundpage │ └── Contents.swift ├── protocol-extension.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── protocol-mutating.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── random-number.xcplaygroundpage │ └── Contents.swift ├── range.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── reflect.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── regex.xcplaygroundpage │ └── Contents.swift ├── selector.xcplaygroundpage │ └── Contents.swift ├── self-anyclass.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── sequence.xcplaygroundpage │ └── Contents.swift ├── singleton.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── static-class.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── string-nsstring.xcplaygroundpage │ └── Contents.swift ├── struct-mutating.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── subscript.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── tail-recursion.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── toll-free.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── tuple.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── type-encode.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── typealias.xcplaygroundpage │ └── Contents.swift ├── unsafe.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── use-self.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── value-reference.xcplaygroundpage │ └── Contents.swift ├── variadic.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline └── where.xcplaygroundpage │ ├── Contents.swift │ └── timeline.xctimeline ├── contents.xcplayground └── playground.xcworkspace ├── contents.xcworkspacedata ├── xcshareddata └── Swifter.xcscmblueprint └── xcuserdata ├── JP20028.xcuserdatad ├── UserInterfaceState.xcuserstate └── userinterfacestate (Wei Wang の競合コピー 2016-09-07).xcuserstate └── onevcat.xcuserdatad ├── UserInterfaceState (Wei Wang の競合コピー 2016-09-07).xcuserstate └── UserInterfaceState.xcuserstate /Swifter.playground/Pages/assert.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let absoluteZeroInCelsius = -273.15 5 | 6 | func convertToKelvin(_ celsius: Double) -> Double { 7 | assert(celsius > absoluteZeroInCelsius, "输入的摄氏温度不能低于绝对零度") 8 | return celsius - absoluteZeroInCelsius 9 | } 10 | 11 | let roomTemperature = convertToKelvin(27) 12 | // roomTemperature = 300.15 13 | 14 | let tooCold = convertToKelvin(-300) 15 | // 运行时错误: 16 | // assertion failed: 17 | // 输入的摄氏温度不能低于绝对零度 : file {YOUR_FILE_PATH}, line {LINE_NUMBER} 18 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/assert.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/associated-object.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | // MyClass.swift 5 | class MyClass { 6 | } 7 | 8 | // MyClassExtension.swift 9 | private var key: Void? 10 | 11 | extension MyClass { 12 | var title: String? { 13 | get { 14 | return objc_getAssociatedObject(self, &key) as? String 15 | } 16 | 17 | set { 18 | objc_setAssociatedObject(self, 19 | &key, newValue, 20 | .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 21 | } 22 | } 23 | } 24 | 25 | 26 | // 测试 27 | func printTitle(_ input: MyClass) { 28 | if let title = input.title { 29 | print("Title: \(title)") 30 | } else { 31 | print("没有设置") 32 | } 33 | } 34 | 35 | let a = MyClass() 36 | printTitle(a) 37 | a.title = "Swifter.tips" 38 | printTitle(a) 39 | 40 | // 输出: 41 | // 没有设置 42 | // Title: Swifter.tips 43 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/associatedtype.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | protocol Food { } 5 | 6 | protocol Animal { 7 | associatedtype F: Food 8 | func eat(_ food: F) 9 | } 10 | 11 | struct Meat: Food { } 12 | struct Grass: Food { } 13 | 14 | struct Tiger: Animal { 15 | func eat(_ food: Meat) { 16 | print("eat \(food)") 17 | } 18 | } 19 | 20 | let meat = Meat() 21 | Tiger().eat(meat) 22 | 23 | struct Sheep: Animal { 24 | func eat(_ food: Grass) { 25 | print("eat \(food)") 26 | } 27 | } 28 | 29 | //func isDangerous(animal: Animal) -> Bool { 30 | // return false 31 | //} 32 | 33 | func isDangerous(animal: T) -> Bool { 34 | if animal is Tiger { 35 | return true 36 | } else { 37 | return false 38 | } 39 | } 40 | 41 | isDangerous(animal: Tiger()) 42 | isDangerous(animal: Sheep()) -------------------------------------------------------------------------------- /Swifter.playground/Pages/autoclosure.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func logIfTrue(_ predicate: () -> Bool) { 5 | if predicate() { 6 | print("True") 7 | } 8 | } 9 | 10 | logIfTrue({return 2 > 1}) 11 | logIfTrue({2 > 1}) 12 | logIfTrue{2 > 1} 13 | 14 | 15 | func logIfTrue(_ predicate: @autoclosure () -> Bool) { 16 | if predicate() { 17 | print("True") 18 | } 19 | } 20 | 21 | logIfTrue(2 > 1) 22 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/class-cluster.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | class Drinking { 5 | typealias LiquidColor = UIColor 6 | var color: LiquidColor { 7 | return .clear 8 | } 9 | 10 | class func drinking(name: String) -> Drinking { 11 | var drinking: Drinking 12 | switch name { 13 | case "Coke": 14 | drinking = Coke() 15 | case "Beer": 16 | drinking = Beer() 17 | default: 18 | drinking = Drinking() 19 | } 20 | 21 | return drinking 22 | } 23 | } 24 | 25 | class Coke: Drinking { 26 | override var color: LiquidColor { 27 | return .black 28 | } 29 | } 30 | 31 | class Beer: Drinking { 32 | override var color: LiquidColor { 33 | return .yellow 34 | } 35 | } 36 | 37 | let coke = Drinking.drinking(name: "Coke") 38 | coke.color // Black 39 | 40 | let beer = Drinking.drinking(name: "Beer") 41 | beer.color // Yellow 42 | 43 | 44 | let cokeClass = NSStringFromClass(type(of: coke)) //Coke 45 | 46 | let beerClass = NSStringFromClass(type(of: beer)) //Beer 47 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/class-cluster.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/closure-ambiguous.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | extension Int { 5 | func times(f: (Int) -> ()) { 6 | print("Int") 7 | for i in 1...self { 8 | f(i) 9 | } 10 | } 11 | } 12 | 13 | 3.times { (i: Int) -> () in 14 | print(i) 15 | } 16 | // 输出: 17 | // Int 18 | // 1 19 | // 2 20 | // 3 21 | 22 | 3.times { i in 23 | print(i) 24 | } 25 | // 输出: 26 | // Int 27 | // 1 28 | // 2 29 | // 3 30 | 31 | 32 | //extension Int { 33 | // func times(f: Void -> Void) { 34 | // print("Void") 35 | // for i in 1...self { 36 | // f() 37 | // } 38 | // } 39 | //} 40 | // Swift 1.2 之前: 41 | // 输出: 42 | // Void 43 | // 44 | // 45 | // 46 | // Swift 1.2 之后由于歧义,无法编译 47 | 48 | //extension Int { 49 | // func times(f: (Int, Int) -> ()) { 50 | // print("Tuple") 51 | // for i in 1...self { 52 | // f(i, i) 53 | // } 54 | // } 55 | //} 56 | // 注释掉开头的 times(f: Int -> ()) 57 | // 3.times { i in 58 | // print(i) 59 | // } 60 | // 输出为 61 | // Tuple 62 | // (1, 1) 63 | // (2, 2) 64 | // (3, 3) 65 | 66 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/currying.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func addOne(num: Int) -> Int { 5 | return num + 1 6 | } 7 | 8 | func addTo(_ adder: Int) -> (Int) -> Int { 9 | return { 10 | num in 11 | return num + adder 12 | } 13 | } 14 | 15 | let addTwo = addTo(2) // addToFour: Int -> Int 16 | let result = addTwo(6) // result = 8 17 | 18 | func greaterThan(_ comparer: Int) -> (Int) -> Bool { 19 | return { $0 > comparer } 20 | } 21 | 22 | let greaterThan10 = greaterThan(10); 23 | 24 | greaterThan10(13) // => true 25 | greaterThan10(9) // => false 26 | 27 | protocol TargetAction { 28 | func performAction() 29 | } 30 | 31 | struct TargetActionWrapper: TargetAction { 32 | weak var target: T? 33 | let action: (T) -> () -> () 34 | 35 | func performAction() -> () { 36 | if let t = target { 37 | action(t)() 38 | } 39 | } 40 | } 41 | 42 | enum ControlEvent { 43 | case TouchUpInside 44 | case ValueChanged 45 | // ... 46 | } 47 | 48 | 49 | class Control { 50 | var actions = [ControlEvent: TargetAction]() 51 | 52 | func setTarget(target: T, 53 | action: @escaping (T) -> () -> (), controlEvent: ControlEvent) { 54 | 55 | actions[controlEvent] = TargetActionWrapper( 56 | target: target, action: action) 57 | } 58 | 59 | func removeTargetForControlEvent(controlEvent: ControlEvent) { 60 | actions[controlEvent] = nil 61 | } 62 | 63 | func performActionForControlEvent(controlEvent: ControlEvent) { 64 | actions[controlEvent]?.performAction() 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/default-param.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func sayHello1(str1: String = "Hello", str2: String, str3: String) { 5 | print(str1 + str2 + str3) 6 | } 7 | 8 | func sayHello2(str1: String, str2: String, str3: String = "World") { 9 | print(str1 + str2 + str3) 10 | } 11 | 12 | sayHello1(str2: " ", str3: "World") 13 | sayHello2(str1: "Hello", str2: " ") 14 | 15 | //输出都是 Hello World 16 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/delegate.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | protocol MyClassDelegate: class { 5 | func method() 6 | } 7 | 8 | class MyClass { 9 | weak var delegate: MyClassDelegate? 10 | } 11 | 12 | class ViewController: UIViewController, MyClassDelegate { 13 | // ... 14 | var someInstance: MyClass! 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | someInstance = MyClass() 20 | someInstance.delegate = self 21 | } 22 | 23 | func method() { 24 | print("Do something") 25 | } 26 | 27 | //... 28 | } 29 | 30 | // weak var delegate: MyClassDelegate? 编译错误 31 | // 'weak' cannot be applied to non-class type 'MyClassDelegate' 32 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/delegate.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/documentation.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A demo method 6 | 7 | - parameter input: An Int number 8 | 9 | - returns: The string represents the input number 10 | */ 11 | func method(input: Int) -> String { 12 | return String(input) 13 | } 14 | 15 | struct Person { 16 | /// name of the person 17 | var name: String 18 | } 19 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/documentation.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/enum-enumerate.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | enum Suit: String { 5 | case spades = "黑桃" 6 | case hearts = "红桃" 7 | case clubs = "草花" 8 | case diamonds = "方片" 9 | } 10 | 11 | enum Rank: Int, CustomStringConvertible { 12 | case ace = 1 13 | case two, three, four, five, six, seven, eight, nine, ten 14 | case jack, queen, king 15 | var description: String { 16 | switch self { 17 | case .ace: 18 | return "A" 19 | case .jack: 20 | return "J" 21 | case .queen: 22 | return "Q" 23 | case .king: 24 | return "K" 25 | default: 26 | return String(self.rawValue) 27 | } 28 | } 29 | } 30 | 31 | protocol EnumeratableEnum { 32 | static var allValues: [Self] {get} 33 | } 34 | 35 | extension Suit: EnumeratableEnum { 36 | static var allValues: [Suit] { 37 | return [.spades, .hearts, .clubs, .diamonds] 38 | } 39 | } 40 | 41 | extension Rank: EnumeratableEnum { 42 | static var allValues: [Rank] { 43 | return [.ace, .two, .three, 44 | .four, .five, .six, 45 | .seven, .eight, .nine, 46 | .ten, .jack, .queen, .king] 47 | } 48 | } 49 | 50 | for suit in Suit.allValues { 51 | for rank in Rank.allValues { 52 | print("\(suit.rawValue)\(rank)") 53 | } 54 | } 55 | 56 | // 输出: 57 | // 黑桃A 58 | // 黑桃2 59 | // 黑桃3 60 | // ... 61 | // 方片K 62 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/enumerate.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let arr: NSArray = [1,2,3,4,5] 5 | var result = 0 6 | 7 | arr.enumerateObjects ({ (num, idx, stop) -> Void in 8 | result += num as! Int 9 | if idx == 2 { 10 | stop.pointee = true 11 | } 12 | }) 13 | print(result) 14 | // 输出:6 15 | 16 | result = 0 17 | for (idx, num) in [1,2,3,4,5].enumerated() { 18 | result += num 19 | if idx == 2 { 20 | break 21 | } 22 | } 23 | print(result) 24 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/equal.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let str1 = "快乐的字符串" 5 | let str2 = "快乐的字符串" 6 | let str3 = "开心的字符串" 7 | 8 | str1 == str2 // true 9 | str1 == str3 // false 10 | 11 | class TodoItem { 12 | let uuid: String 13 | var title: String 14 | 15 | init(uuid: String, title: String) { 16 | self.uuid = uuid 17 | self.title = title 18 | } 19 | } 20 | 21 | extension TodoItem: Equatable { 22 | 23 | } 24 | 25 | func ==(lhs: TodoItem, rhs: TodoItem) -> Bool { 26 | return lhs.uuid == rhs.uuid 27 | } 28 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/equal.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/error-handle.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let d = NSData() 5 | 6 | do { 7 | try d.write(toFile: "Hello", options: []) 8 | } catch let error as NSError { 9 | print ("Error: \(error.domain)") 10 | } 11 | 12 | enum LoginError: Error { 13 | case UserNotFound, UserPasswordNotMatch 14 | } 15 | 16 | func login(user: String, password: String) throws { 17 | let users = [String: String]() 18 | 19 | if !users.keys.contains(user) { 20 | throw LoginError.UserNotFound 21 | } 22 | 23 | if users[user] != password { 24 | throw LoginError.UserPasswordNotMatch 25 | } 26 | 27 | print("Login successfully.") 28 | } 29 | 30 | do { 31 | try login(user: "onevcat", password: "123") 32 | } catch LoginError.UserNotFound { 33 | print("UserNotFound") 34 | } catch LoginError.UserPasswordNotMatch { 35 | print("UserPasswordNotMatch") 36 | } 37 | 38 | // Do something with login user 39 | 40 | enum E: Error { 41 | case Negative 42 | } 43 | 44 | func methodThrowsWhenPassingNegative(number: Int) throws -> Int { 45 | if number < 0 { 46 | throw E.Negative 47 | } 48 | return number 49 | } 50 | 51 | if let num = try? methodThrowsWhenPassingNegative(number: 100) { 52 | print(type(of: num)) 53 | } else { 54 | print("failed") 55 | } 56 | 57 | // Never do this! 58 | func methodThrowsWhenPassingNegative1(number: Int) throws -> Int? { 59 | if number < 0 { 60 | throw E.Negative 61 | } 62 | if number == 0 { 63 | return nil 64 | } 65 | return number 66 | } 67 | 68 | if let num = try? methodThrowsWhenPassingNegative1(number: 0) { 69 | print(type(of: num)) 70 | } else { 71 | print("failed") 72 | } 73 | 74 | func methodThrows(num: Int) throws { 75 | if num < 0 { 76 | print("Throwing!") 77 | throw E.Negative 78 | } 79 | print("Executed!") 80 | } 81 | 82 | func methodRethrows(num: Int, f: (Int) throws -> ()) rethrows { 83 | try f(num) 84 | } 85 | 86 | do { 87 | try methodRethrows(num: 1, f: methodThrows) 88 | } catch _ { 89 | 90 | } 91 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/escaping.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import PlaygroundSupport 4 | 5 | PlaygroundPage.current.needsIndefiniteExecution = true 6 | 7 | func doWork(block: ()->()) { 8 | block() 9 | } 10 | 11 | func doWorkAsync(block: @escaping ()->()) { 12 | DispatchQueue.main.async { 13 | block() 14 | } 15 | } 16 | 17 | class S { 18 | var foo = "foo" 19 | 20 | func method1() { 21 | doWork { 22 | print(foo) 23 | } 24 | foo = "bar" 25 | } 26 | 27 | func method2() { 28 | doWorkAsync { 29 | print(self.foo) 30 | } 31 | foo = "bar" 32 | } 33 | 34 | func method3() { 35 | doWorkAsync { 36 | [weak self] _ in 37 | print(self?.foo) 38 | } 39 | foo = "bar" 40 | } 41 | } 42 | 43 | S().method1() 44 | // foo 45 | 46 | S().method2() 47 | // bar 48 | 49 | S().method3() 50 | // nil 51 | 52 | protocol P { 53 | func work(b: @escaping ()->()) 54 | } 55 | 56 | class C: P { 57 | func work(b: @escaping () -> ()) { 58 | DispatchQueue.main.async { 59 | print("in C") 60 | b() 61 | } 62 | } 63 | } 64 | 65 | C().work { 66 | print("work!") 67 | } 68 | // in C 69 | // work! 70 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/extension-generic.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | extension Array { 5 | var random: Element? { 6 | return self.count != 0 ? 7 | self[Int(arc4random_uniform(UInt32(self.count)))] : 8 | nil 9 | } 10 | 11 | func appendRandomDescription 12 | (_ input: U) -> String { 13 | 14 | if let element = self.random { 15 | return "\(element) " + input.description 16 | } else { 17 | return "empty array" 18 | } 19 | } 20 | } 21 | 22 | let languages = ["Swift","ObjC","C++","Java"] 23 | languages.random! 24 | // 随机输出是这四个字符串中的某个 25 | 26 | let ranks = [1,2,3,4] 27 | ranks.random! 28 | // 随机输出是这四个数字中的某个 29 | 30 | languages.appendRandomDescription(ranks.random!) 31 | // 随机组合 languages 和 ranks 中的各一个元素,然后输出 32 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/fatalError.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | enum MyEnum { 5 | case Value1,Value2,Value3 6 | } 7 | 8 | 9 | func check(someValue: MyEnum) -> String { 10 | switch someValue { 11 | case .Value1: 12 | return "OK" 13 | case .Value2: 14 | return "Maybe OK" 15 | default: 16 | // 这个分支没有返回 String,也能编译通过 17 | fatalError("Should not show!") 18 | } 19 | } 20 | 21 | class MyClass { 22 | func methodMustBeImplementedInSubclass() { 23 | fatalError("这个方法必须在子类中被重写") 24 | } 25 | } 26 | 27 | class YourClass: MyClass { 28 | override func methodMustBeImplementedInSubclass() { 29 | print("YourClass 实现了该方法") 30 | } 31 | } 32 | 33 | class TheirClass: MyClass { 34 | func someOtherMethod() { 35 | 36 | } 37 | } 38 | 39 | YourClass().methodMustBeImplementedInSubclass() 40 | // YourClass 实现了该方法 41 | 42 | TheirClass().methodMustBeImplementedInSubclass() 43 | // 这个方法必须在子类中被重写 44 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/fatalError.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/final.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class Parent { 5 | 6 | final func method() { 7 | print("开始配置") 8 | // ..必要的代码 9 | 10 | methodImpl() 11 | 12 | // ..必要的代码 13 | print("结束配置") 14 | } 15 | 16 | func methodImpl() { 17 | fatalError("子类必须实现这个方法") 18 | // 或者也可以给出默认实现 19 | } 20 | 21 | } 22 | 23 | class Child: Parent { 24 | override func methodImpl() { 25 | //..子类的业务逻辑 26 | print("Setup in Child") 27 | } 28 | } 29 | 30 | let c = Child() 31 | c.method() -------------------------------------------------------------------------------- /Swifter.playground/Pages/final.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/func-dispatch.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class MyClass { 5 | func method(number: Int) -> Int { 6 | return number + 1 7 | } 8 | } 9 | 10 | let object = MyClass() 11 | let result = object.method(number: 1) 12 | // result = 2 13 | 14 | 15 | let f = MyClass.method 16 | let object1 = MyClass() 17 | let result1 = f(object)(1) 18 | 19 | 20 | class MyClass1 { 21 | func method(number: Int) -> Int { 22 | return number + 1 23 | } 24 | 25 | class func method(number: Int) -> Int { 26 | return number 27 | } 28 | } 29 | 30 | let f1 = MyClass1.method 31 | // class func method 的版本 32 | 33 | let f2: (Int) -> Int = MyClass1.method 34 | // 和 f1 相同 35 | 36 | let f3: (MyClass1) -> (Int) -> Int = MyClass1.method 37 | // func method 的柯里化版本 38 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/func-dispatch.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/func-params.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import Foundation 4 | 5 | func incrementor1(variable: Int) -> Int { 6 | return variable + 1 7 | } 8 | 9 | let a = incrementor1(variable: 4) 10 | 11 | func incrementor2(variable: Int) -> Int { 12 | var num = variable 13 | num += 1 14 | return num 15 | } 16 | 17 | var luckyNumber = 7 18 | let newNumber = incrementor2(variable: luckyNumber) 19 | // newNumber = 8 20 | 21 | print(luckyNumber) 22 | // luckyNumber 还是 7 23 | 24 | func incrementor3(variable: inout Int) { 25 | variable += 1 26 | } 27 | 28 | luckyNumber = 7 29 | incrementor3(variable: &luckyNumber) 30 | 31 | print(luckyNumber) 32 | // luckyNumber = 8 33 | 34 | func makeIncrementor(addNumber: Int) -> ((inout Int) -> ()) { 35 | func incrementor(variable: inout Int) -> () { 36 | variable += addNumber; 37 | } 38 | return incrementor; 39 | } 40 | 41 | var input = 10 42 | let incrementor = makeIncrementor(addNumber: 2) 43 | incrementor(&input) 44 | print(input) 45 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/func-params.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/gcd-delay.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import PlaygroundSupport 4 | 5 | PlaygroundPage.current.needsIndefiniteExecution = true 6 | 7 | // 创建目标队列 8 | let workingQueue = DispatchQueue(label: "my_queue") 9 | 10 | 11 | // 派发到刚创建的队列中,GCD 会负责进行线程调度 12 | 13 | workingQueue.async { 14 | // 在 workingQueue 中异步进行 15 | print("努力工作") 16 | Thread.sleep(forTimeInterval: 2) // 模拟两秒的执行时间 17 | 18 | DispatchQueue.main.async { 19 | // 返回到主线程更新 UI 20 | print("结束工作,更新 UI") 21 | } 22 | } 23 | 24 | let time: TimeInterval = 2.0 25 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + time) { 26 | print("2 秒后输出") 27 | } 28 | 29 | import Foundation 30 | 31 | typealias Task = (_ cancel : Bool) -> Void 32 | 33 | func delay(_ time: TimeInterval, task: @escaping ()->()) -> Task? { 34 | 35 | func dispatch_later(block: @escaping ()->()) { 36 | let t = DispatchTime.now() + time 37 | DispatchQueue.main.asyncAfter(deadline: t, execute: block) 38 | } 39 | 40 | 41 | 42 | var closure: (()->Void)? = task 43 | var result: Task? 44 | 45 | let delayedClosure: Task = { 46 | cancel in 47 | if let internalClosure = closure { 48 | if (cancel == false) { 49 | DispatchQueue.main.async(execute: internalClosure) 50 | } 51 | } 52 | closure = nil 53 | result = nil 54 | } 55 | 56 | result = delayedClosure 57 | 58 | dispatch_later { 59 | if let delayedClosure = result { 60 | delayedClosure(false) 61 | } 62 | } 63 | 64 | return result; 65 | 66 | } 67 | 68 | func cancel(_ task: Task?) { 69 | task?(true) 70 | } 71 | 72 | delay(2) { print("2 秒后输出") } 73 | 74 | let task = delay(5) { print("拨打 110") } 75 | 76 | // 仔细想一想.. 77 | // 还是取消为妙.. 78 | cancel(task) 79 | 80 | 81 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/general.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | // Press ⌘1 (Or use View -> Navigators menu) to open Project Navigation to choose the file. 5 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/general.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/hash.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let num = 19 5 | print(num.hashValue) // 19 6 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/hash.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/indirect-nested-enum.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | //class Node { 5 | // let value: T? 6 | // let next: Node? 7 | // 8 | // init(value: T?, next: Node?) { 9 | // self.value = value 10 | // self.next = next 11 | // } 12 | //} 13 | // 14 | //let list = Node(value: 1, 15 | // next: Node(value: 2, 16 | // next: Node(value: 3, 17 | // next: Node(value: 4, next: nil)))) 18 | 19 | 20 | indirect enum LinkedList { 21 | case empty 22 | case node(Element, LinkedList) 23 | 24 | func removing(_ element: Element) -> LinkedList { 25 | guard case let .node(value, next) = self else { 26 | return .empty 27 | } 28 | return value == element ? 29 | next : LinkedList.node(value, next.removing(element)) 30 | } 31 | } 32 | 33 | let linkedList = LinkedList.node(1, .node(2, .node(3, .node(4, .empty)))) 34 | print(linkedList) 35 | 36 | let result1 = linkedList.removing(2) 37 | print(result1) 38 | 39 | let result2 = linkedList.removing(100) 40 | print(result2) 41 | 42 | let emptyList = LinkedList.empty 43 | let result3 = emptyList.removing(12) 44 | print(result3) 45 | 46 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/indirect-nested-enum.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/init-keyword.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import Foundation 4 | 5 | class ClassA { 6 | let numA: Int 7 | required init(num: Int) { 8 | numA = num 9 | } 10 | 11 | convenience init(bigNum: Bool) { 12 | self.init(num: bigNum ? 10000 : 1) 13 | } 14 | } 15 | 16 | class ClassB: ClassA { 17 | let numB: Int 18 | 19 | required init(num: Int) { 20 | numB = num + 1 21 | super.init(num: num) 22 | } 23 | } 24 | 25 | let anObj = ClassB(bigNum: true) 26 | // anObj.numA = 10000, anObj.numB = 10001 -------------------------------------------------------------------------------- /Swifter.playground/Pages/init-keyword.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/init-nil.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let url = NSURL(string: "ht tp://swifter。tips") 5 | print(url) 6 | 7 | extension Int { 8 | init?(fromString: String) { 9 | self = 0 10 | var digit = fromString.characters.count - 1 11 | for c in fromString.characters { 12 | var number = 0 13 | if let n = Int(String(c)) { 14 | number = n 15 | } else { 16 | switch c { 17 | case "一": number = 1 18 | case "二": number = 2 19 | case "三": number = 3 20 | case "四": number = 4 21 | case "五": number = 5 22 | case "六": number = 6 23 | case "七": number = 7 24 | case "八": number = 8 25 | case "九": number = 9 26 | case "零": number = 0 27 | default: return nil 28 | } 29 | } 30 | 31 | self = self + number * Int(pow(10, Double(digit))) 32 | digit = digit - 1 33 | } 34 | } 35 | } 36 | 37 | let number1 = Int(fromString: "12") 38 | // {Some 12} 39 | 40 | let number2 = Int(fromString: "三二五") 41 | // {Some 325} 42 | 43 | let number3 = Int(fromString: "七9八") 44 | // {Some 798} 45 | 46 | let number4 = Int(fromString: "吃了么") 47 | // nil 48 | 49 | let number5 = Int(fromString: "1a4n") 50 | // nil -------------------------------------------------------------------------------- /Swifter.playground/Pages/init-nil.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/init.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | class Cat { 3 | var name: String 4 | init() { 5 | name = "cat" 6 | } 7 | } 8 | 9 | class Tiger: Cat { 10 | let power: Int 11 | override init() { 12 | power = 10 13 | super.init() 14 | name = "tiger" 15 | } 16 | } 17 | 18 | class Cat1 { 19 | var name: String 20 | init() { 21 | name = "cat" 22 | } 23 | } 24 | 25 | class Tiger1: Cat1 { 26 | let power: Int 27 | override init() { 28 | power = 10 29 | // 如果我们不需要打改变 name 的话, 30 | // 虽然我们没有显式地对 super.init() 进行调用 31 | // 不过由于这是初始化的最后了,Swift 替我们自动完成了 32 | } 33 | } 34 | 35 | let cat = Cat1() 36 | 37 | let tiger = Tiger1() 38 | 39 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/init.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/instance-type.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let date1 = NSDate() 5 | let name1: AnyClass! = object_getClass(date1) 6 | print(name1) 7 | // 输出: 8 | // __NSDate 9 | 10 | 11 | let date2 = NSDate() 12 | let name2 = type(of: date2) 13 | print(name2) 14 | // 输出: 15 | // __NSDate 16 | 17 | let string = "Hello" 18 | let name = type(of: string) 19 | print(name) 20 | debugPrint(name) 21 | // 输出: 22 | // Swift.String 23 | 24 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/instance-type.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/intropection.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class ClassA: NSObject { } 5 | class ClassB: ClassA { } 6 | 7 | let obj1: NSObject = ClassB() 8 | let obj2: NSObject = ClassB() 9 | 10 | obj1.isKind(of: ClassA.self) // true 11 | obj2.isMember(of: ClassA.self) // false 12 | 13 | let obj: AnyObject = ClassB() 14 | 15 | if (obj is ClassA) { 16 | print("属于 ClassA") 17 | } 18 | 19 | if (obj is ClassB) { 20 | print("属于 ClassB") 21 | } 22 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/intropection.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/json.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let jsonString = "{\"menu\": {" + 5 | "\"id\": \"file\"," + 6 | "\"value\": \"File\"," + 7 | "\"popup\": {" + 8 | "\"menuitem\": [" + 9 | "{\"value\": \"New\", \"onclick\": \"CreateNewDoc()\"}," + 10 | "{\"value\": \"Open\", \"onclick\": \"OpenDoc()\"}," + 11 | "{\"value\": \"Close\", \"onclick\": \"CloseDoc()\"}" + 12 | "]" + 13 | "}" + 14 | "}}" 15 | 16 | let json: Any = try! JSONSerialization.jsonObject( 17 | with: jsonString.data(using: .utf8, allowLossyConversion: true)!, 18 | options: []) 19 | 20 | if let jsonDic = json as? NSDictionary { 21 | if let menu = jsonDic["menu"] as? [String: AnyObject] { 22 | if let popup: AnyObject = menu["popup"] { 23 | if let popupDic = popup as? [String: AnyObject] { 24 | if let menuItems: AnyObject = popupDic["menuitem"] { 25 | if let menuItemsArr = menuItems as? [AnyObject] { 26 | if let item0 = menuItemsArr[0] 27 | as? [String: AnyObject] { 28 | if let value: AnyObject = item0["value"] { 29 | print(value) 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | 39 | if let jsonDic = json as? NSDictionary, 40 | let menu = jsonDic["menu"] as? [String: AnyObject], 41 | let popup = menu["popup"], 42 | let popupDic = popup as? [String: AnyObject], 43 | let menuItems = popupDic["menuitem"], 44 | let menuItemsArr = menuItems as? [AnyObject], 45 | let item0 = menuItemsArr[0] as? [String: AnyObject], 46 | let value = item0["value"] 47 | { 48 | print(value) 49 | } 50 | 51 | if let value = JSON(json)["menu"]["popup"]["menuitem"][0]["value"].string { 52 | print(value) 53 | } 54 | 55 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/json.xcplaygroundpage/Sources/SwiftyJSON.swift: -------------------------------------------------------------------------------- 1 | // SwiftyJSON.swift 2 | // 3 | // Copyright (c) 2014 Ruoyu Fu, Pinglin Tang 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | // MARK: - Error 26 | 27 | ///Error domain 28 | public let ErrorDomain: String = "SwiftyJSONErrorDomain" 29 | 30 | ///Error code 31 | public let ErrorUnsupportedType: Int = 999 32 | public let ErrorIndexOutOfBounds: Int = 900 33 | public let ErrorWrongType: Int = 901 34 | public let ErrorNotExist: Int = 500 35 | public let ErrorInvalidJSON: Int = 490 36 | 37 | // MARK: - JSON Type 38 | 39 | /** 40 | JSON's type definitions. 41 | 42 | See http://www.json.org 43 | */ 44 | public enum Type :Int{ 45 | 46 | case number 47 | case string 48 | case bool 49 | case array 50 | case dictionary 51 | case null 52 | case unknown 53 | } 54 | 55 | // MARK: - JSON Base 56 | 57 | public struct JSON { 58 | 59 | /** 60 | Creates a JSON using the data. 61 | 62 | - parameter data: The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary 63 | - parameter opt: The JSON serialization reading options. `.AllowFragments` by default. 64 | - parameter error: error The NSErrorPointer used to return the error. `nil` by default. 65 | 66 | - returns: The created JSON 67 | */ 68 | public init(data:Data, options opt: JSONSerialization.ReadingOptions = .allowFragments, error: NSErrorPointer? = nil) { 69 | do { 70 | let object: Any = try JSONSerialization.jsonObject(with: data, options: opt) 71 | self.init(object) 72 | } catch let aError as NSError { 73 | if error != nil { 74 | error??.pointee = aError 75 | } 76 | self.init(NSNull()) 77 | } 78 | } 79 | 80 | /** 81 | Create a JSON from JSON string 82 | - parameter string: Normal json string like '{"a":"b"}' 83 | 84 | - returns: The created JSON 85 | */ 86 | public static func parse(_ string:String) -> JSON { 87 | return string.data(using: String.Encoding.utf8) 88 | .flatMap({JSON(data: $0)}) ?? JSON(NSNull()) 89 | } 90 | 91 | /** 92 | Creates a JSON using the object. 93 | 94 | - parameter object: The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity. 95 | 96 | - returns: The created JSON 97 | */ 98 | public init(_ object: Any) { 99 | self.object = object 100 | } 101 | 102 | /** 103 | Creates a JSON from a [JSON] 104 | 105 | - parameter jsonArray: A Swift array of JSON objects 106 | 107 | - returns: The created JSON 108 | */ 109 | public init(_ jsonArray:[JSON]) { 110 | self.init(jsonArray.map { $0.object }) 111 | } 112 | 113 | /** 114 | Creates a JSON from a [String: JSON] 115 | 116 | - parameter jsonDictionary: A Swift dictionary of JSON objects 117 | 118 | - returns: The created JSON 119 | */ 120 | public init(_ jsonDictionary:[String: JSON]) { 121 | var dictionary = [String: Any](minimumCapacity: jsonDictionary.count) 122 | for (key, json) in jsonDictionary { 123 | dictionary[key] = json.object 124 | } 125 | self.init(dictionary) 126 | } 127 | 128 | /// fileprivate object 129 | fileprivate var rawArray: [Any] = [] 130 | fileprivate var rawDictionary: [String : Any] = [:] 131 | fileprivate var rawString: String = "" 132 | fileprivate var rawNumber: NSNumber = 0 133 | fileprivate var rawNull: NSNull = NSNull() 134 | /// fileprivate type 135 | fileprivate var _type: Type = .null 136 | /// prviate error 137 | fileprivate var _error: NSError? = nil 138 | 139 | /// Object in JSON 140 | public var object: Any { 141 | get { 142 | switch self.type { 143 | case .array: 144 | return self.rawArray 145 | case .dictionary: 146 | return self.rawDictionary 147 | case .string: 148 | return self.rawString 149 | case .number: 150 | return self.rawNumber 151 | case .bool: 152 | return self.rawNumber 153 | default: 154 | return self.rawNull 155 | } 156 | } 157 | set { 158 | _error = nil 159 | switch newValue { 160 | case let number as NSNumber: 161 | if number.isBool { 162 | _type = .bool 163 | } else { 164 | _type = .number 165 | } 166 | self.rawNumber = number 167 | case let string as String: 168 | _type = .string 169 | self.rawString = string 170 | case _ as NSNull: 171 | _type = .null 172 | case let array as [Any]: 173 | _type = .array 174 | self.rawArray = array 175 | case let dictionary as [String : Any]: 176 | _type = .dictionary 177 | self.rawDictionary = dictionary 178 | default: 179 | _type = .unknown 180 | _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"]) 181 | } 182 | } 183 | } 184 | 185 | /// json type 186 | public var type: Type { get { return _type } } 187 | 188 | /// Error in JSON 189 | public var error: NSError? { get { return self._error } } 190 | 191 | /// The static null json 192 | @available(*, unavailable, renamed:"null") 193 | public static var nullJSON: JSON { get { return null } } 194 | public static var null: JSON { get { return JSON(NSNull()) } } 195 | } 196 | 197 | public enum JSONIndex:Comparable { 198 | case array(Int) 199 | case dictionary(DictionaryIndex) 200 | case null 201 | } 202 | 203 | public func ==(lhs: JSONIndex, rhs: JSONIndex) -> Bool { 204 | switch (lhs, rhs) { 205 | case (.array(let left), .array(let right)): 206 | return left == right 207 | case (.dictionary(let left), .dictionary(let right)): 208 | return left == right 209 | default: 210 | return false 211 | } 212 | } 213 | 214 | public func <(lhs: JSONIndex, rhs: JSONIndex) -> Bool { 215 | switch (lhs, rhs) { 216 | case (.array(let left), .array(let right)): 217 | return left < right 218 | case (.dictionary(let left), .dictionary(let right)): 219 | return left < right 220 | default: 221 | return false 222 | } 223 | } 224 | 225 | 226 | extension JSON: Collection { 227 | 228 | public typealias Index = JSONIndex 229 | 230 | public var startIndex: Index{ 231 | switch type { 232 | case .array: 233 | return .array(rawArray.startIndex) 234 | case .dictionary: 235 | return .dictionary(dictionaryValue.startIndex) 236 | default: 237 | return .null 238 | } 239 | } 240 | 241 | public var endIndex: Index{ 242 | switch type { 243 | case .array: 244 | return .array(rawArray.endIndex) 245 | case .dictionary: 246 | return .dictionary(dictionaryValue.endIndex) 247 | default: 248 | return .null 249 | } 250 | } 251 | 252 | public func index(after i: Index) -> Index { 253 | switch i { 254 | case .array(let idx): 255 | return .array(rawArray.index(after: idx)) 256 | case .dictionary(let idx): 257 | return .dictionary(dictionaryValue.index(after: idx)) 258 | default: 259 | return .null 260 | } 261 | 262 | } 263 | 264 | public subscript (position: Index) -> (String, JSON) { 265 | switch position { 266 | case .array(let idx): 267 | return (String(idx), JSON(self.rawArray[idx])) 268 | case .dictionary(let idx): 269 | return dictionaryValue[idx] 270 | default: 271 | return ("", JSON.null) 272 | } 273 | } 274 | 275 | 276 | } 277 | 278 | // MARK: - Subscript 279 | 280 | /** 281 | * To mark both String and Int can be used in subscript. 282 | */ 283 | public enum JSONKey { 284 | case index(Int) 285 | case key(String) 286 | } 287 | 288 | public protocol JSONSubscriptType { 289 | var jsonKey:JSONKey { get } 290 | } 291 | 292 | extension Int: JSONSubscriptType { 293 | public var jsonKey:JSONKey { 294 | return JSONKey.index(self) 295 | } 296 | } 297 | 298 | extension String: JSONSubscriptType { 299 | public var jsonKey:JSONKey { 300 | return JSONKey.key(self) 301 | } 302 | } 303 | 304 | extension JSON { 305 | 306 | /// If `type` is `.Array`, return json whose object is `array[index]`, otherwise return null json with error. 307 | fileprivate subscript(index index: Int) -> JSON { 308 | get { 309 | if self.type != .array { 310 | var r = JSON.null 311 | r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"]) 312 | return r 313 | } else if index >= 0 && index < self.rawArray.count { 314 | return JSON(self.rawArray[index]) 315 | } else { 316 | var r = JSON.null 317 | r._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"]) 318 | return r 319 | } 320 | } 321 | set { 322 | if self.type == .array { 323 | if self.rawArray.count > index && newValue.error == nil { 324 | self.rawArray[index] = newValue.object 325 | } 326 | } 327 | } 328 | } 329 | 330 | /// If `type` is `.Dictionary`, return json whose object is `dictionary[key]` , otherwise return null json with error. 331 | fileprivate subscript(key key: String) -> JSON { 332 | get { 333 | var r = JSON.null 334 | if self.type == .dictionary { 335 | if let o = self.rawDictionary[key] { 336 | r = JSON(o) 337 | } else { 338 | r._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"]) 339 | } 340 | } else { 341 | r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"]) 342 | } 343 | return r 344 | } 345 | set { 346 | if self.type == .dictionary && newValue.error == nil { 347 | self.rawDictionary[key] = newValue.object 348 | } 349 | } 350 | } 351 | 352 | /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`. 353 | fileprivate subscript(sub sub: JSONSubscriptType) -> JSON { 354 | get { 355 | switch sub.jsonKey { 356 | case .index(let index): return self[index: index] 357 | case .key(let key): return self[key: key] 358 | } 359 | } 360 | set { 361 | switch sub.jsonKey { 362 | case .index(let index): self[index: index] = newValue 363 | case .key(let key): self[key: key] = newValue 364 | } 365 | } 366 | } 367 | 368 | /** 369 | Find a json in the complex data structuresby using the Int/String's array. 370 | 371 | - parameter path: The target json's path. Example: 372 | 373 | let json = JSON[data] 374 | let path = [9,"list","person","name"] 375 | let name = json[path] 376 | 377 | The same as: let name = json[9]["list"]["person"]["name"] 378 | 379 | - returns: Return a json found by the path or a null json with error 380 | */ 381 | public subscript(path: [JSONSubscriptType]) -> JSON { 382 | get { 383 | return path.reduce(self) { $0[sub: $1] } 384 | } 385 | set { 386 | switch path.count { 387 | case 0: 388 | return 389 | case 1: 390 | self[sub:path[0]].object = newValue.object 391 | default: 392 | var aPath = path; aPath.remove(at: 0) 393 | var nextJSON = self[sub: path[0]] 394 | nextJSON[aPath] = newValue 395 | self[sub: path[0]] = nextJSON 396 | } 397 | } 398 | } 399 | 400 | /** 401 | Find a json in the complex data structures by using the Int/String's array. 402 | 403 | - parameter path: The target json's path. Example: 404 | 405 | let name = json[9,"list","person","name"] 406 | 407 | The same as: let name = json[9]["list"]["person"]["name"] 408 | 409 | - returns: Return a json found by the path or a null json with error 410 | */ 411 | public subscript(path: JSONSubscriptType...) -> JSON { 412 | get { 413 | return self[path] 414 | } 415 | set { 416 | self[path] = newValue 417 | } 418 | } 419 | } 420 | 421 | // MARK: - LiteralConvertible 422 | 423 | extension JSON: Swift.StringLiteralConvertible { 424 | 425 | public init(stringLiteral value: StringLiteralType) { 426 | self.init(value) 427 | } 428 | 429 | public init(extendedGraphemeClusterLiteral value: StringLiteralType) { 430 | self.init(value) 431 | } 432 | 433 | public init(unicodeScalarLiteral value: StringLiteralType) { 434 | self.init(value) 435 | } 436 | } 437 | 438 | extension JSON: Swift.IntegerLiteralConvertible { 439 | 440 | public init(integerLiteral value: IntegerLiteralType) { 441 | self.init(value) 442 | } 443 | } 444 | 445 | extension JSON: Swift.BooleanLiteralConvertible { 446 | 447 | public init(booleanLiteral value: BooleanLiteralType) { 448 | self.init(value) 449 | } 450 | } 451 | 452 | extension JSON: Swift.FloatLiteralConvertible { 453 | 454 | public init(floatLiteral value: FloatLiteralType) { 455 | self.init(value) 456 | } 457 | } 458 | 459 | extension JSON: Swift.DictionaryLiteralConvertible { 460 | 461 | public init(dictionaryLiteral elements: (String, Any)...) { 462 | self.init(elements.reduce([String : Any](minimumCapacity: elements.count)){(dictionary: [String : Any], element:(String, Any)) -> [String : Any] in 463 | var d = dictionary 464 | d[element.0] = element.1 465 | return d 466 | }) 467 | } 468 | } 469 | 470 | extension JSON: Swift.ArrayLiteralConvertible { 471 | 472 | public init(arrayLiteral elements: Any...) { 473 | self.init(elements) 474 | } 475 | } 476 | 477 | extension JSON: Swift.NilLiteralConvertible { 478 | 479 | public init(nilLiteral: ()) { 480 | self.init(NSNull()) 481 | } 482 | } 483 | 484 | // MARK: - Raw 485 | 486 | extension JSON: Swift.RawRepresentable { 487 | 488 | public init?(rawValue: Any) { 489 | if JSON(rawValue).type == .unknown { 490 | return nil 491 | } else { 492 | self.init(rawValue) 493 | } 494 | } 495 | 496 | public var rawValue: Any { 497 | return self.object 498 | } 499 | 500 | public func rawData(options opt: JSONSerialization.WritingOptions = JSONSerialization.WritingOptions(rawValue: 0)) throws -> Data { 501 | guard JSONSerialization.isValidJSONObject(self.object) else { 502 | throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: "JSON is invalid"]) 503 | } 504 | 505 | return try JSONSerialization.data(withJSONObject: self.object, options: opt) 506 | } 507 | 508 | public func rawString(_ encoding: String.Encoding = String.Encoding.utf8, options opt: JSONSerialization.WritingOptions = .prettyPrinted) -> String? { 509 | switch self.type { 510 | case .array, .dictionary: 511 | do { 512 | let data = try self.rawData(options: opt) 513 | return String(data: data, encoding: encoding) 514 | } catch _ { 515 | return nil 516 | } 517 | case .string: 518 | return self.rawString 519 | case .number: 520 | return self.rawNumber.stringValue 521 | case .bool: 522 | return self.rawNumber.boolValue.description 523 | case .null: 524 | return "null" 525 | default: 526 | return nil 527 | } 528 | } 529 | } 530 | 531 | // MARK: - Printable, DebugPrintable 532 | 533 | extension JSON: Swift.CustomStringConvertible, Swift.CustomDebugStringConvertible { 534 | 535 | public var description: String { 536 | if let string = self.rawString(options:.prettyPrinted) { 537 | return string 538 | } else { 539 | return "unknown" 540 | } 541 | } 542 | 543 | public var debugDescription: String { 544 | return description 545 | } 546 | } 547 | 548 | // MARK: - Array 549 | 550 | extension JSON { 551 | 552 | //Optional [JSON] 553 | public var array: [JSON]? { 554 | get { 555 | if self.type == .array { 556 | return self.rawArray.map{ JSON($0) } 557 | } else { 558 | return nil 559 | } 560 | } 561 | } 562 | 563 | //Non-optional [JSON] 564 | public var arrayValue: [JSON] { 565 | get { 566 | return self.array ?? [] 567 | } 568 | } 569 | 570 | //Optional [Any] 571 | public var arrayObject: [Any]? { 572 | get { 573 | switch self.type { 574 | case .array: 575 | return self.rawArray 576 | default: 577 | return nil 578 | } 579 | } 580 | set { 581 | if let array = newValue { 582 | self.object = array 583 | } else { 584 | self.object = NSNull() 585 | } 586 | } 587 | } 588 | } 589 | 590 | // MARK: - Dictionary 591 | 592 | extension JSON { 593 | 594 | //Optional [String : JSON] 595 | public var dictionary: [String : JSON]? { 596 | if self.type == .dictionary { 597 | 598 | return self.rawDictionary.reduce([String : JSON]()) { (dictionary: [String : JSON], element: (String, Any)) -> [String : JSON] in 599 | var d = dictionary 600 | d[element.0] = JSON(element.1) 601 | return d 602 | } 603 | } else { 604 | return nil 605 | } 606 | } 607 | 608 | //Non-optional [String : JSON] 609 | public var dictionaryValue: [String : JSON] { 610 | return self.dictionary ?? [:] 611 | } 612 | 613 | //Optional [String : Any] 614 | public var dictionaryObject: [String : Any]? { 615 | get { 616 | switch self.type { 617 | case .dictionary: 618 | return self.rawDictionary 619 | default: 620 | return nil 621 | } 622 | } 623 | set { 624 | if let v = newValue { 625 | self.object = v 626 | } else { 627 | self.object = NSNull() 628 | } 629 | } 630 | } 631 | } 632 | 633 | // MARK: - Bool 634 | 635 | extension JSON { 636 | 637 | //Optional bool 638 | public var bool: Bool? { 639 | get { 640 | switch self.type { 641 | case .bool: 642 | return self.rawNumber.boolValue 643 | default: 644 | return nil 645 | } 646 | } 647 | set { 648 | if let newValue = newValue { 649 | self.object = NSNumber(value: newValue) 650 | } else { 651 | self.object = NSNull() 652 | } 653 | } 654 | } 655 | 656 | //Non-optional bool 657 | public var boolValue: Bool { 658 | get { 659 | switch self.type { 660 | case .bool, .number, .string: 661 | return (self.object as AnyObject).boolValue 662 | default: 663 | return false 664 | } 665 | } 666 | set { 667 | self.object = NSNumber(value: newValue) 668 | } 669 | } 670 | } 671 | 672 | // MARK: - String 673 | 674 | extension JSON { 675 | 676 | //Optional string 677 | public var string: String? { 678 | get { 679 | switch self.type { 680 | case .string: 681 | return self.object as? String 682 | default: 683 | return nil 684 | } 685 | } 686 | set { 687 | if let newValue = newValue { 688 | self.object = NSString(string:newValue) 689 | } else { 690 | self.object = NSNull() 691 | } 692 | } 693 | } 694 | 695 | //Non-optional string 696 | public var stringValue: String { 697 | get { 698 | switch self.type { 699 | case .string: 700 | return self.object as? String ?? "" 701 | case .number: 702 | return (self.object as AnyObject).stringValue 703 | case .bool: 704 | return (self.object as? Bool).map { String($0) } ?? "" 705 | default: 706 | return "" 707 | } 708 | } 709 | set { 710 | self.object = NSString(string:newValue) 711 | } 712 | } 713 | } 714 | 715 | // MARK: - Number 716 | extension JSON { 717 | 718 | //Optional number 719 | public var number: NSNumber? { 720 | get { 721 | switch self.type { 722 | case .number, .bool: 723 | return self.rawNumber 724 | default: 725 | return nil 726 | } 727 | } 728 | set { 729 | self.object = newValue ?? NSNull() 730 | } 731 | } 732 | 733 | //Non-optional number 734 | public var numberValue: NSNumber { 735 | get { 736 | switch self.type { 737 | case .string: 738 | let decimal = NSDecimalNumber(string: self.object as? String) 739 | if decimal == NSDecimalNumber.notANumber { // indicates parse error 740 | return NSDecimalNumber.zero 741 | } 742 | return decimal 743 | case .number, .bool: 744 | return self.object as? NSNumber ?? NSNumber(value: 0) 745 | default: 746 | return NSNumber(value: 0.0) 747 | } 748 | } 749 | set { 750 | self.object = newValue 751 | } 752 | } 753 | } 754 | 755 | //MARK: - Null 756 | extension JSON { 757 | 758 | public var null: NSNull? { 759 | get { 760 | switch self.type { 761 | case .null: 762 | return self.rawNull 763 | default: 764 | return nil 765 | } 766 | } 767 | set { 768 | self.object = NSNull() 769 | } 770 | } 771 | public func exists() -> Bool{ 772 | if let errorValue = error, errorValue.code == ErrorNotExist{ 773 | return false 774 | } 775 | return true 776 | } 777 | } 778 | 779 | //MARK: - URL 780 | extension JSON { 781 | 782 | //Optional URL 783 | public var URL: Foundation.URL? { 784 | get { 785 | switch self.type { 786 | case .string: 787 | if let encodedString_ = self.rawString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) { 788 | return Foundation.URL(string: encodedString_) 789 | } else { 790 | return nil 791 | } 792 | default: 793 | return nil 794 | } 795 | } 796 | set { 797 | self.object = newValue?.absoluteString ?? NSNull() 798 | } 799 | } 800 | } 801 | 802 | // MARK: - Int, Double, Float, Int8, Int16, Int32, Int64 803 | 804 | extension JSON { 805 | 806 | public var double: Double? { 807 | get { 808 | return self.number?.doubleValue 809 | } 810 | set { 811 | if let newValue = newValue { 812 | self.object = NSNumber(value: newValue) 813 | } else { 814 | self.object = NSNull() 815 | } 816 | } 817 | } 818 | 819 | public var doubleValue: Double { 820 | get { 821 | return self.numberValue.doubleValue 822 | } 823 | set { 824 | self.object = NSNumber(value: newValue) 825 | } 826 | } 827 | 828 | public var float: Float? { 829 | get { 830 | return self.number?.floatValue 831 | } 832 | set { 833 | if let newValue = newValue { 834 | self.object = NSNumber(value: newValue) 835 | } else { 836 | self.object = NSNull() 837 | } 838 | } 839 | } 840 | 841 | public var floatValue: Float { 842 | get { 843 | return self.numberValue.floatValue 844 | } 845 | set { 846 | self.object = NSNumber(value: newValue) 847 | } 848 | } 849 | 850 | public var int: Int? { 851 | get { 852 | return self.number?.intValue 853 | } 854 | set { 855 | if let newValue = newValue { 856 | self.object = NSNumber(value: newValue) 857 | } else { 858 | self.object = NSNull() 859 | } 860 | } 861 | } 862 | 863 | public var intValue: Int { 864 | get { 865 | return self.numberValue.intValue 866 | } 867 | set { 868 | self.object = NSNumber(value: newValue) 869 | } 870 | } 871 | 872 | public var uInt: UInt? { 873 | get { 874 | return self.number?.uintValue 875 | } 876 | set { 877 | if let newValue = newValue { 878 | self.object = NSNumber(value: newValue) 879 | } else { 880 | self.object = NSNull() 881 | } 882 | } 883 | } 884 | 885 | public var uIntValue: UInt { 886 | get { 887 | return self.numberValue.uintValue 888 | } 889 | set { 890 | self.object = NSNumber(value: newValue) 891 | } 892 | } 893 | 894 | public var int8: Int8? { 895 | get { 896 | return self.number?.int8Value 897 | } 898 | set { 899 | if let newValue = newValue { 900 | self.object = NSNumber(value: newValue) 901 | } else { 902 | self.object = NSNull() 903 | } 904 | } 905 | } 906 | 907 | public var int8Value: Int8 { 908 | get { 909 | return self.numberValue.int8Value 910 | } 911 | set { 912 | self.object = NSNumber(value: newValue) 913 | } 914 | } 915 | 916 | public var uInt8: UInt8? { 917 | get { 918 | return self.number?.uint8Value 919 | } 920 | set { 921 | if let newValue = newValue { 922 | self.object = NSNumber(value: newValue) 923 | } else { 924 | self.object = NSNull() 925 | } 926 | } 927 | } 928 | 929 | public var uInt8Value: UInt8 { 930 | get { 931 | return self.numberValue.uint8Value 932 | } 933 | set { 934 | self.object = NSNumber(value: newValue) 935 | } 936 | } 937 | 938 | public var int16: Int16? { 939 | get { 940 | return self.number?.int16Value 941 | } 942 | set { 943 | if let newValue = newValue { 944 | self.object = NSNumber(value: newValue) 945 | } else { 946 | self.object = NSNull() 947 | } 948 | } 949 | } 950 | 951 | public var int16Value: Int16 { 952 | get { 953 | return self.numberValue.int16Value 954 | } 955 | set { 956 | self.object = NSNumber(value: newValue) 957 | } 958 | } 959 | 960 | public var uInt16: UInt16? { 961 | get { 962 | return self.number?.uint16Value 963 | } 964 | set { 965 | if let newValue = newValue { 966 | self.object = NSNumber(value: newValue) 967 | } else { 968 | self.object = NSNull() 969 | } 970 | } 971 | } 972 | 973 | public var uInt16Value: UInt16 { 974 | get { 975 | return self.numberValue.uint16Value 976 | } 977 | set { 978 | self.object = NSNumber(value: newValue) 979 | } 980 | } 981 | 982 | public var int32: Int32? { 983 | get { 984 | return self.number?.int32Value 985 | } 986 | set { 987 | if let newValue = newValue { 988 | self.object = NSNumber(value: newValue) 989 | } else { 990 | self.object = NSNull() 991 | } 992 | } 993 | } 994 | 995 | public var int32Value: Int32 { 996 | get { 997 | return self.numberValue.int32Value 998 | } 999 | set { 1000 | self.object = NSNumber(value: newValue) 1001 | } 1002 | } 1003 | 1004 | public var uInt32: UInt32? { 1005 | get { 1006 | return self.number?.uint32Value 1007 | } 1008 | set { 1009 | if let newValue = newValue { 1010 | self.object = NSNumber(value: newValue) 1011 | } else { 1012 | self.object = NSNull() 1013 | } 1014 | } 1015 | } 1016 | 1017 | public var uInt32Value: UInt32 { 1018 | get { 1019 | return self.numberValue.uint32Value 1020 | } 1021 | set { 1022 | self.object = NSNumber(value: newValue) 1023 | } 1024 | } 1025 | 1026 | public var int64: Int64? { 1027 | get { 1028 | return self.number?.int64Value 1029 | } 1030 | set { 1031 | if let newValue = newValue { 1032 | self.object = NSNumber(value: newValue) 1033 | } else { 1034 | self.object = NSNull() 1035 | } 1036 | } 1037 | } 1038 | 1039 | public var int64Value: Int64 { 1040 | get { 1041 | return self.numberValue.int64Value 1042 | } 1043 | set { 1044 | self.object = NSNumber(value: newValue) 1045 | } 1046 | } 1047 | 1048 | public var uInt64: UInt64? { 1049 | get { 1050 | return self.number?.uint64Value 1051 | } 1052 | set { 1053 | if let newValue = newValue { 1054 | self.object = NSNumber(value: newValue) 1055 | } else { 1056 | self.object = NSNull() 1057 | } 1058 | } 1059 | } 1060 | 1061 | public var uInt64Value: UInt64 { 1062 | get { 1063 | return self.numberValue.uint64Value 1064 | } 1065 | set { 1066 | self.object = NSNumber(value: newValue) 1067 | } 1068 | } 1069 | } 1070 | 1071 | //MARK: - Comparable 1072 | extension JSON : Swift.Comparable {} 1073 | 1074 | public func ==(lhs: JSON, rhs: JSON) -> Bool { 1075 | 1076 | switch (lhs.type, rhs.type) { 1077 | case (.number, .number): 1078 | return lhs.rawNumber == rhs.rawNumber 1079 | case (.string, .string): 1080 | return lhs.rawString == rhs.rawString 1081 | case (.bool, .bool): 1082 | return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue 1083 | case (.array, .array): 1084 | return lhs.rawArray as NSArray == rhs.rawArray as NSArray 1085 | case (.dictionary, .dictionary): 1086 | return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary 1087 | case (.null, .null): 1088 | return true 1089 | default: 1090 | return false 1091 | } 1092 | } 1093 | 1094 | public func <=(lhs: JSON, rhs: JSON) -> Bool { 1095 | 1096 | switch (lhs.type, rhs.type) { 1097 | case (.number, .number): 1098 | return lhs.rawNumber <= rhs.rawNumber 1099 | case (.string, .string): 1100 | return lhs.rawString <= rhs.rawString 1101 | case (.bool, .bool): 1102 | return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue 1103 | case (.array, .array): 1104 | return lhs.rawArray as NSArray == rhs.rawArray as NSArray 1105 | case (.dictionary, .dictionary): 1106 | return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary 1107 | case (.null, .null): 1108 | return true 1109 | default: 1110 | return false 1111 | } 1112 | } 1113 | 1114 | public func >=(lhs: JSON, rhs: JSON) -> Bool { 1115 | 1116 | switch (lhs.type, rhs.type) { 1117 | case (.number, .number): 1118 | return lhs.rawNumber >= rhs.rawNumber 1119 | case (.string, .string): 1120 | return lhs.rawString >= rhs.rawString 1121 | case (.bool, .bool): 1122 | return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue 1123 | case (.array, .array): 1124 | return lhs.rawArray as NSArray == rhs.rawArray as NSArray 1125 | case (.dictionary, .dictionary): 1126 | return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary 1127 | case (.null, .null): 1128 | return true 1129 | default: 1130 | return false 1131 | } 1132 | } 1133 | 1134 | public func >(lhs: JSON, rhs: JSON) -> Bool { 1135 | 1136 | switch (lhs.type, rhs.type) { 1137 | case (.number, .number): 1138 | return lhs.rawNumber > rhs.rawNumber 1139 | case (.string, .string): 1140 | return lhs.rawString > rhs.rawString 1141 | default: 1142 | return false 1143 | } 1144 | } 1145 | 1146 | public func <(lhs: JSON, rhs: JSON) -> Bool { 1147 | 1148 | switch (lhs.type, rhs.type) { 1149 | case (.number, .number): 1150 | return lhs.rawNumber < rhs.rawNumber 1151 | case (.string, .string): 1152 | return lhs.rawString < rhs.rawString 1153 | default: 1154 | return false 1155 | } 1156 | } 1157 | 1158 | fileprivate let trueNumber = NSNumber(value: true) 1159 | fileprivate let falseNumber = NSNumber(value: false) 1160 | fileprivate let trueObjCType = String(cString: trueNumber.objCType) 1161 | fileprivate let falseObjCType = String(cString: falseNumber.objCType) 1162 | 1163 | // MARK: - NSNumber: Comparable 1164 | 1165 | extension NSNumber { 1166 | var isBool:Bool { 1167 | get { 1168 | let objCType = String(cString: self.objCType) 1169 | if (self.compare(trueNumber) == ComparisonResult.orderedSame && objCType == trueObjCType) 1170 | || (self.compare(falseNumber) == ComparisonResult.orderedSame && objCType == falseObjCType){ 1171 | return true 1172 | } else { 1173 | return false 1174 | } 1175 | } 1176 | } 1177 | } 1178 | 1179 | func ==(lhs: NSNumber, rhs: NSNumber) -> Bool { 1180 | switch (lhs.isBool, rhs.isBool) { 1181 | case (false, true): 1182 | return false 1183 | case (true, false): 1184 | return false 1185 | default: 1186 | return lhs.compare(rhs) == ComparisonResult.orderedSame 1187 | } 1188 | } 1189 | 1190 | func !=(lhs: NSNumber, rhs: NSNumber) -> Bool { 1191 | return !(lhs == rhs) 1192 | } 1193 | 1194 | func <(lhs: NSNumber, rhs: NSNumber) -> Bool { 1195 | 1196 | switch (lhs.isBool, rhs.isBool) { 1197 | case (false, true): 1198 | return false 1199 | case (true, false): 1200 | return false 1201 | default: 1202 | return lhs.compare(rhs) == ComparisonResult.orderedAscending 1203 | } 1204 | } 1205 | 1206 | func >(lhs: NSNumber, rhs: NSNumber) -> Bool { 1207 | 1208 | switch (lhs.isBool, rhs.isBool) { 1209 | case (false, true): 1210 | return false 1211 | case (true, false): 1212 | return false 1213 | default: 1214 | return lhs.compare(rhs) == ComparisonResult.orderedDescending 1215 | } 1216 | } 1217 | 1218 | func <=(lhs: NSNumber, rhs: NSNumber) -> Bool { 1219 | 1220 | switch (lhs.isBool, rhs.isBool) { 1221 | case (false, true): 1222 | return false 1223 | case (true, false): 1224 | return false 1225 | default: 1226 | return lhs.compare(rhs) != ComparisonResult.orderedDescending 1227 | } 1228 | } 1229 | 1230 | func >=(lhs: NSNumber, rhs: NSNumber) -> Bool { 1231 | 1232 | switch (lhs.isBool, rhs.isBool) { 1233 | case (false, true): 1234 | return false 1235 | case (true, false): 1236 | return false 1237 | default: 1238 | return lhs.compare(rhs) != ComparisonResult.orderedAscending 1239 | } 1240 | } 1241 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/kvo.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import PlaygroundSupport 3 | 4 | PlaygroundPage.current.needsIndefiniteExecution = true 5 | 6 | class MyClass: NSObject { 7 | dynamic var date = Date() 8 | } 9 | 10 | class MyClass1: NSObject { 11 | var date = Date() 12 | } 13 | 14 | class MyChildClass: MyClass1 { 15 | dynamic override var date: Date { 16 | get { return super.date } 17 | set { super.date = newValue } 18 | } 19 | } 20 | 21 | private var myContext = 0 22 | 23 | class Class: NSObject { 24 | 25 | var myObject: MyClass! 26 | 27 | override init() { 28 | super.init() 29 | myObject = MyClass() 30 | print("初始化 MyClass,当前日期: \(myObject.date)") 31 | myObject.addObserver(self, 32 | forKeyPath: "date", 33 | options: .new, 34 | context: &myContext) 35 | 36 | delay(3) { 37 | self.myObject.date = Date() 38 | } 39 | } 40 | 41 | override func observeValue(forKeyPath keyPath: String?, 42 | of object: Any?, 43 | change: [NSKeyValueChangeKey : Any]?, 44 | context: UnsafeMutableRawPointer?) 45 | { 46 | if let change = change, context == &myContext { 47 | let newDate = change[.newKey] 48 | print("日期发生变化 \(newDate)") 49 | } 50 | } 51 | } 52 | 53 | let obj = Class() -------------------------------------------------------------------------------- /Swifter.playground/Pages/kvo.xcplaygroundpage/Sources/delay.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias Task = (_ cancel : Bool) -> Void 4 | 5 | public func delay(_ time: TimeInterval, task: @escaping ()->()) -> Task? { 6 | 7 | func dispatch_later(block: @escaping ()->()) { 8 | let t = DispatchTime.now() + time 9 | DispatchQueue.main.asyncAfter(deadline: t, execute: block) 10 | } 11 | 12 | 13 | 14 | var closure: (()->Void)? = task 15 | var result: Task? 16 | 17 | let delayedClosure: Task = { 18 | cancel in 19 | if let internalClosure = closure { 20 | if (cancel == false) { 21 | DispatchQueue.main.async(execute: internalClosure) 22 | } 23 | } 24 | closure = nil 25 | result = nil 26 | } 27 | 28 | result = delayedClosure 29 | 30 | dispatch_later { 31 | if let delayedClosure = result { 32 | delayedClosure(false) 33 | } 34 | } 35 | 36 | return result; 37 | 38 | } 39 | 40 | func cancel(_ task: Task?) { 41 | task?(true) 42 | } 43 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/lazy.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class ClassA { 5 | lazy var str: String = { 6 | let str = "Hello" 7 | print("只在首次访问输出") 8 | return str 9 | }() 10 | } 11 | 12 | print("Creating object") 13 | let obj = ClassA() 14 | 15 | print("Accessing str") 16 | obj.str 17 | 18 | print("Accessing str again") 19 | obj.str 20 | 21 | let data1 = 1...3 22 | let result1 = data1.map { 23 | (i: Int) -> Int in 24 | print("正在处理 \(i)") 25 | return i * 2 26 | } 27 | 28 | print("准备访问结果") 29 | for i in result1 { 30 | print("操作后结果为 \(i)") 31 | } 32 | 33 | print("操作完毕") 34 | 35 | 36 | let data2 = 1...3 37 | let result2 = data2.lazy.map { 38 | (i: Int) -> Int in 39 | print("正在处理 \(i)") 40 | return i * 2 41 | } 42 | 43 | print("准备访问结果") 44 | for i in result2 { 45 | print("操作后结果为 \(i)") 46 | } 47 | 48 | print("操作完毕") 49 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/lazy.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/literal.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import Foundation 4 | 5 | let aNumber = 3 6 | let aString = "Hello" 7 | let aBool = true 8 | 9 | let anArray = [1,2,3] 10 | let aDictionary = ["key1": "value1", "key2": "value2"] 11 | 12 | typealias ALC = ExpressibleByArrayLiteral 13 | typealias BLC = ExpressibleByBooleanLiteral 14 | typealias DLC = ExpressibleByDictionaryLiteral 15 | typealias FLC = ExpressibleByFloatLiteral 16 | typealias NLC = ExpressibleByNilLiteral 17 | typealias ILC = ExpressibleByIntegerLiteral 18 | typealias SLC = ExpressibleByStringLiteral 19 | 20 | enum MyBool: Int { 21 | case myTrue, myFalse 22 | } 23 | 24 | extension MyBool: ExpressibleByBooleanLiteral { 25 | init(booleanLiteral value: Bool) { 26 | self = value ? .myTrue : .myFalse 27 | } 28 | } 29 | 30 | let myTrue: MyBool = true 31 | let myFalse: MyBool = false 32 | 33 | myTrue.rawValue // 0 34 | myFalse.rawValue // 1 35 | 36 | //class Person { 37 | // let name: String 38 | // init(name value: String) { 39 | // self.name = value 40 | // } 41 | //} 42 | 43 | class Person: ExpressibleByStringLiteral { 44 | let name: String 45 | init(name value: String) { 46 | self.name = value 47 | } 48 | 49 | required convenience init(stringLiteral value: String) { 50 | self.init(name: value) 51 | } 52 | 53 | required convenience init(extendedGraphemeClusterLiteral value: String) { 54 | self.init(name: value) 55 | } 56 | 57 | required convenience init(unicodeScalarLiteral value: String) { 58 | self.init(name: value) 59 | } 60 | } 61 | 62 | let p: Person = "xiaoMing" 63 | print(p.name) 64 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/literal.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/local-scope.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import PlaygroundSupport 3 | 4 | func local(_ closure: ()->()) { 5 | closure() 6 | } 7 | 8 | func loadView() { 9 | 10 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 480)) 11 | view.backgroundColor = .white 12 | 13 | local { 14 | let titleLabel = UILabel(frame: CGRect(x: 150, y: 30, width: 200, height: 40)) 15 | titleLabel.textColor = .red 16 | titleLabel.text = "Title" 17 | view.addSubview(titleLabel) 18 | } 19 | 20 | local { 21 | let textLabel = UILabel(frame: CGRect(x: 150, y: 80, width: 200, height: 40)) 22 | textLabel.textColor = .red 23 | textLabel.text = "Text" 24 | view.addSubview(textLabel) 25 | } 26 | 27 | PlaygroundPage.current.liveView = view 28 | } 29 | 30 | loadView() 31 | 32 | let titleLabel: UILabel = { 33 | let label = UILabel(frame: CGRect(x: 150, y: 30, width: 200, height: 40)) 34 | label.textColor = .red 35 | label.text = "Title" 36 | return label 37 | }() -------------------------------------------------------------------------------- /Swifter.playground/Pages/local-scope.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/lock.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func myMethod(anObj: AnyObject!) { 5 | objc_sync_enter(anObj) 6 | 7 | // 在 enter 和 exit 之间 anObj 不会被其他线程改变 8 | 9 | objc_sync_exit(anObj) 10 | } 11 | 12 | func synchronized(_ lock: AnyObject, closure: () -> ()) { 13 | objc_sync_enter(lock) 14 | closure() 15 | objc_sync_exit(lock) 16 | } 17 | 18 | func myMethodLocked(anObj: AnyObject!) { 19 | synchronized(anObj) { 20 | // 在括号内 anObj 不会被其他线程改变 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/log.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func method() { 5 | //... 6 | print("文件名:Test.swift, 方法名:method,这是一条输出") 7 | //... 8 | } 9 | 10 | method() 11 | 12 | func printLog(_ message: T, 13 | file: String = #file, 14 | method: String = #function, 15 | line: Int = #line) 16 | { 17 | print("\((file as NSString).lastPathComponent)[\(line)], \(method): \(message)") 18 | } 19 | 20 | // Test.swift 21 | func method1() { 22 | //... 23 | printLog("这是一条输出") 24 | //... 25 | } 26 | 27 | method1() 28 | 29 | func printLogDebug(_ message: T, 30 | file: String = #file, 31 | method: String = #function, 32 | line: Int = #line) 33 | { 34 | #if DEBUG 35 | print("\((file as NSString).lastPathComponent)[\(line)], \(method): \(message)") 36 | #endif 37 | } 38 | 39 | func method2() { 40 | //... 41 | printLogDebug("这又是一条输出") 42 | //... 43 | } 44 | 45 | method2() 46 | // No Output 47 | 48 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/math-number.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func circlePerimeter(radius: Double) -> Double { 5 | return 2 * M_PI * radius 6 | } 7 | 8 | func yPosition(dy: Double, angle: Double) -> Double { 9 | return dy * tan(angle) 10 | } 11 | 12 | 1.797693134862315e+308 < Double.infinity // true 13 | 1.797693134862316e+308 < Double.infinity // false 14 | 15 | let a = 0.0 / 0.0 16 | let b = sqrt(-1.0) 17 | let c = 0.0 * Double.infinity 18 | 19 | let num = Double.nan 20 | if num == num { 21 | print("Num is \(num)") 22 | } else { 23 | print("NaN") 24 | } 25 | 26 | // 输出: 27 | // NaN 28 | 29 | if num.isNaN { 30 | print("NaN") 31 | } 32 | // 输出: 33 | // NaN 34 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/math-number.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/memory-retain-cycle.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import Foundation 4 | 5 | /// 1 6 | class A: NSObject { 7 | let b: B 8 | override init() { 9 | b = B() 10 | super.init() 11 | b.a = self 12 | } 13 | 14 | deinit { 15 | print("A deinit") 16 | } 17 | } 18 | 19 | class B: NSObject { 20 | weak var a: A? = nil 21 | deinit { 22 | print("B deinit") 23 | } 24 | } 25 | 26 | var obj: A? = A() 27 | obj = nil 28 | 29 | 30 | /// 2 31 | // RequestManager.swift 32 | class RequestManager: RequestHandler { 33 | 34 | @objc func requestFinished() { 35 | print("请求完成") 36 | } 37 | 38 | func sendRequest() { 39 | let req = Request() 40 | req.delegate = self 41 | 42 | req.send() 43 | } 44 | } 45 | 46 | // Request.swift 47 | @objc protocol RequestHandler { 48 | @objc optional func requestFinished() 49 | } 50 | 51 | class Request { 52 | weak var delegate: RequestHandler!; 53 | 54 | func send() { 55 | // 发送请求 56 | // 一般来说会将 req 的引用传递给网络框架 57 | } 58 | 59 | func gotResponse() { 60 | // 请求返回 61 | delegate?.requestFinished?() 62 | } 63 | } 64 | 65 | /// 3 66 | class Person { 67 | let name: String 68 | 69 | // lazy var printName: ()->() = { 70 | // print("The name is \(self.name)") 71 | // } 72 | 73 | lazy var printName: ()->() = { 74 | [weak self] in 75 | if let strongSelf = self { 76 | print("The name is \(strongSelf.name)") 77 | } 78 | } 79 | 80 | init(personName: String) { 81 | name = personName 82 | } 83 | 84 | deinit { 85 | print("Person deinit \(self.name)") 86 | } 87 | } 88 | 89 | var xiaoMing: Person? = Person(personName: "XiaoMing") 90 | xiaoMing!.printName() 91 | xiaoMing = nil 92 | 93 | // 输出: 94 | // The name is XiaoMing 95 | // Person deinit XiaoMing 96 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/multi-collection.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let numbers = [1,2,3,4,5] 5 | // numbers 的类型是 [Int] 6 | 7 | let strings = ["hello", "world"] 8 | // strings 的类型是 [String] 9 | 10 | import UIKit 11 | 12 | // [Any] 13 | let mixed1: [Any] = [1, "two", 3] 14 | 15 | // [NSObject] 16 | let objectArray = [1 as NSObject, "two" as NSObject, 3 as NSObject] 17 | 18 | let any = mixed1[0] // Any 类型 19 | let nsObject = objectArray[0] // NSObject 类型 20 | 21 | let mixed2: [CustomStringConvertible] = [1, "two", 3] 22 | 23 | for obj in mixed2 { 24 | print(obj.description) 25 | } 26 | 27 | enum IntOrString { 28 | case IntValue(Int) 29 | case StringValue(String) 30 | } 31 | 32 | let mixed3 = [IntOrString.IntValue(1), 33 | IntOrString.StringValue("two"), 34 | IntOrString.IntValue(3)] 35 | 36 | for value in mixed3 { 37 | switch value { 38 | case let .IntValue(i): 39 | print(i * 2) 40 | case let .StringValue(s): 41 | print(s.capitalized) 42 | } 43 | } 44 | 45 | // 输出: 46 | // 2 47 | // Two 48 | // 6 49 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/multi-collection.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/multi-method.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class Pet {} 5 | class Cat: Pet {} 6 | class Dog: Pet {} 7 | 8 | func printPet(_ pet: Pet) { 9 | print("Pet") 10 | } 11 | 12 | func printPet(_ cat: Cat) { 13 | print("Meow") 14 | } 15 | 16 | func printPet(_ dog: Dog) { 17 | print("Bark") 18 | } 19 | 20 | printPet(Cat()) // Meow 21 | printPet(Dog()) // Bark 22 | printPet(Pet()) // Pet 23 | 24 | func printThem(_ pet: Pet, _ cat: Cat) { 25 | printPet(pet) 26 | printPet(cat) 27 | } 28 | 29 | printThem(Dog(), Cat()) 30 | 31 | // 输出: 32 | // Pet 33 | // Meow 34 | 35 | func printThemAgain(_ pet: Pet, _ cat: Cat) { 36 | if let aCat = pet as? Cat { 37 | printPet(aCat) 38 | } else if let aDog = pet as? Dog { 39 | printPet(aDog) 40 | } 41 | printPet(cat) 42 | } 43 | 44 | printThemAgain(Dog(), Cat()) 45 | // 输出: 46 | // Bark 47 | // Meow 48 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/multiple-optional.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | var string: String? = "string" 5 | var anotherString: String?? = string 6 | 7 | var literalOptional: String?? = "string" 8 | 9 | var aNil: String? = nil 10 | 11 | var anotherNil: String?? = aNil 12 | var literalNil: String?? = nil 13 | 14 | if let a = anotherNil { 15 | // This will output. 16 | print("anotherNil") 17 | } 18 | 19 | if let b = literalNil { 20 | // This will not output. 21 | print("literalNil") 22 | } 23 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/nsnull.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | // 假设 jsonValue 是从一个 JSON 中取出的 NSNull 5 | let jsonValue: AnyObject = NSNull() 6 | 7 | if let string = jsonValue as? String { 8 | print(string.hasPrefix("a")) 9 | } else { 10 | print("不能解析") 11 | } 12 | 13 | // 输出: 14 | // 不能解析 15 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/nsnull.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/objc-dynamic.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | @objc(MyClass) 5 | class 我的类: NSObject { 6 | @objc(greeting:) 7 | func 打招呼(名字: String) { 8 | print("哈喽,\(名字)") 9 | } 10 | } 11 | 12 | 我的类().打招呼(名字: "小明") -------------------------------------------------------------------------------- /Swifter.playground/Pages/objc-protocol.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import Foundation 4 | 5 | @objc protocol OptionalProtocol1 { 6 | @objc optional func optionalMethod() 7 | } 8 | 9 | @objc protocol OptionalProtocol2 { 10 | @objc optional func optionalMethod() // 可选 11 | func necessaryMethod() // 必须 12 | @objc optional func anotherOptionalMethod() // 可选 13 | } 14 | 15 | class MyClass1: OptionalProtocol1 { 16 | 17 | } 18 | 19 | //class MyClass2: OptionalProtocol2 { 20 | // func necessaryMethod() { 21 | // print("Default Implementation") 22 | // } 23 | //} 24 | 25 | class MyClass2: NSObject, OptionalProtocol2 { 26 | func necessaryMethod() { 27 | print("Implemented in Class2") 28 | } 29 | } 30 | 31 | 32 | protocol OptionalProtocol3 { 33 | func optionalMethod() // 可选 34 | func necessaryMethod() // 必须 35 | func anotherOptionalMethod() // 可选 36 | } 37 | 38 | extension OptionalProtocol3 { 39 | func optionalMethod() { 40 | print("Implemented in extension") 41 | } 42 | 43 | func anotherOptionalMethod() { 44 | print("Implemented in extension") 45 | } 46 | } 47 | 48 | class MyClass3: OptionalProtocol3 { 49 | func necessaryMethod() { 50 | print("Implemented in Class3") 51 | } 52 | 53 | func optionalMethod() { 54 | print("Implemented in Class3") 55 | } 56 | } 57 | 58 | let obj = MyClass3() 59 | obj.necessaryMethod() 60 | obj.optionalMethod() 61 | obj.anotherOptionalMethod() 62 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/operator.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | struct Vector2D { 5 | var x = 0.0 6 | var y = 0.0 7 | } 8 | 9 | let v1 = Vector2D(x: 2.0, y: 3.0) 10 | let v2 = Vector2D(x: 1.0, y: 4.0) 11 | let v3 = Vector2D(x: v1.x + v2.x, y: v1.y + v2.y) 12 | // v3 为 {x 3.0, y 7.0} 13 | 14 | func +(left: Vector2D, right: Vector2D) -> Vector2D { 15 | return Vector2D(x: left.x + right.x, y: left.y + right.y) 16 | } 17 | 18 | let v4 = v1 + v2 19 | // v4 为 {x 3.0, y 7.0} 20 | 21 | precedencegroup DotProductPrecedence { 22 | associativity: none 23 | higherThan: MultiplicationPrecedence 24 | } 25 | 26 | infix operator +*: DotProductPrecedence 27 | 28 | func +* (left: Vector2D, right: Vector2D) -> Double { 29 | return left.x * right.x + left.y * right.y 30 | } 31 | 32 | let result = v1 +* v2 33 | // 输出为 14.0 34 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/operator.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/optional-chaining.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import Foundation 4 | 5 | class Toy { 6 | let name: String 7 | init(name: String) { 8 | self.name = name 9 | } 10 | } 11 | 12 | class Pet { 13 | var toy: Toy? 14 | } 15 | 16 | class Child { 17 | var pet: Pet? 18 | } 19 | 20 | let xiaoming = Child() 21 | 22 | let toyName = xiaoming.pet?.toy?.name 23 | 24 | if let toyName = xiaoming.pet?.toy?.name { 25 | // 太好了,小明既有宠物,而且宠物还正好有个玩具 26 | } 27 | 28 | extension Toy { 29 | func play() { 30 | //... 31 | } 32 | } 33 | 34 | xiaoming.pet?.toy?.play() 35 | 36 | //let playClosure = {(child: Child) -> () in child.pet?.toy?.play()} //返回值将永远不为 nil 37 | let playClosure = {(child: Child) -> ()? in child.pet?.toy?.play()} 38 | 39 | if let result: () = playClosure(xiaoming) { 40 | print("好开心~") 41 | } else { 42 | print("没有玩具可以玩 :(") 43 | } -------------------------------------------------------------------------------- /Swifter.playground/Pages/optional-chaining.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/optional-map.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let arr = [1,2,3] 5 | let doubled = arr.map{ 6 | $0 * 2 7 | } 8 | 9 | print(doubled) 10 | // 输出: 11 | // [2,4,6] 12 | 13 | let num: Int? = 3 14 | let result = num.map { 15 | $0 * 2 16 | } 17 | 18 | result 19 | // result 为 {Some 6} -------------------------------------------------------------------------------- /Swifter.playground/Pages/optional-map.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/options.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | UIView.animate(withDuration: 0.3, 5 | delay: 0.0, 6 | options: [.curveEaseIn, .allowUserInteraction], 7 | animations: {}, 8 | completion: nil) 9 | 10 | struct YourOption: OptionSet { 11 | let rawValue: UInt 12 | static let none = YourOption(rawValue: 0) 13 | static let option1 = YourOption(rawValue: 1) 14 | static let option2 = YourOption(rawValue: 1 << 1) 15 | //... 16 | } 17 | 18 | YourOption.option1 19 | 20 | [YourOption.option1, YourOption.option2] 21 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/options.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/output-format.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let a = 3; 5 | let b = 1.234567 // 我们在这里不去区分 float 和 Double 了 6 | let c = "Hello" 7 | print("int:\(a) double:\(b) string:\(c)") 8 | // 输出: 9 | // int:3 double:1.234567 string:Hello 10 | 11 | let format = String(format:"%.2f",b) 12 | print("double:\(format)") 13 | // 输出: 14 | // double:1.23 15 | 16 | extension Double { 17 | func format(_ f: String) -> String { 18 | return String(format: "%\(f)f", self) 19 | } 20 | } 21 | 22 | let f = ".2" 23 | print("double:\(b.format(f))") 24 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/overflow.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class MyClass { 5 | var a: Int = 1 6 | func method() { 7 | a = a * 100000 8 | a = a * 100000 9 | a = a * 100000 10 | print(a) 11 | } 12 | } 13 | 14 | MyClass().method() 15 | 16 | // 64 位环境 (iPhone 5s 及以上) 17 | // 1,000,000,000,000,000 18 | 19 | // 32 位环境 (iPhone 5c 及以下) 20 | // 崩溃 21 | 22 | //func method() { 23 | // var max = Int.max 24 | // max = max + 1 25 | //} 26 | 27 | var max = Int.max 28 | max = max &+ 1 29 | 30 | // 64 位系统下 31 | // max = -9,223,372,036,854,775,808 32 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/overflow.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/pattern-match.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import Foundation 4 | 5 | let password = "akfuv(3" 6 | switch password { 7 | case "akfuv(3": print("密码通过") 8 | default: print("验证失败") 9 | } 10 | 11 | let num: Int? = nil 12 | switch num { 13 | case nil: print("没值") 14 | default: print("\(num!)") 15 | } 16 | 17 | let x = 0.5 18 | switch x { 19 | case -1.0...1.0: print("区间内") 20 | default: print("区间外") 21 | } 22 | 23 | func ~=(pattern: NSRegularExpression, input: String) -> Bool { 24 | return pattern.numberOfMatches(in: input, 25 | options: [], 26 | range: NSRange(location: 0, length: input.characters.count)) > 0 27 | } 28 | 29 | prefix operator ~/ 30 | 31 | prefix func ~/(pattern: String) throws -> NSRegularExpression { 32 | return try NSRegularExpression(pattern: pattern, options: []) 33 | } 34 | 35 | let contact = ("http://onevcat.com", "onev@onevcat.com") 36 | 37 | let mailRegex: NSRegularExpression 38 | let siteRegex: NSRegularExpression 39 | 40 | mailRegex = try ~/"^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$" 41 | siteRegex = try ~/"^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?$" 42 | 43 | switch contact { 44 | case (siteRegex, mailRegex): print("同时拥有有效的网站和邮箱") 45 | case (_, mailRegex): print("只拥有有效的邮箱") 46 | case (siteRegex, _): print("只拥有有效的网站") 47 | default: print("嘛都没有") 48 | } 49 | 50 | // 输出 51 | // 同时拥有网站和邮箱 52 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/playground-delay.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import PlaygroundSupport 4 | 5 | PlaygroundPage.current.needsIndefiniteExecution = true 6 | 7 | class MyClass { 8 | @objc func callMe() { 9 | print("Hi") 10 | } 11 | } 12 | 13 | let object = MyClass() 14 | 15 | Timer.scheduledTimer(timeInterval: 1, target: object, 16 | selector: #selector(MyClass.callMe), userInfo: nil, repeats: true) 17 | 18 | let url = URL(string: "http://httpbin.org/get")! 19 | 20 | let getTask = URLSession.shared.dataTask(with: url) { 21 | (data, response, error) in 22 | let dictionary = try! JSONSerialization.jsonObject(with: data!, options: []) 23 | 24 | print(dictionary) 25 | } 26 | 27 | getTask.resume() -------------------------------------------------------------------------------- /Swifter.playground/Pages/playground-liveview.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | import PlaygroundSupport 4 | 5 | 6 | class ViewController: UITableViewController { 7 | override func viewDidLoad() { 8 | super.viewDidLoad() 9 | view.backgroundColor = .cyan 10 | } 11 | } 12 | 13 | extension ViewController { 14 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 15 | return 30 16 | } 17 | 18 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 19 | let cell = UITableViewCell() 20 | cell.textLabel?.text = String(indexPath.row) 21 | return cell 22 | } 23 | } 24 | 25 | extension ViewController { 26 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 27 | print("Select: \(indexPath.row)") 28 | } 29 | } 30 | 31 | //let label = UILabel(frame: CGRect(x: 0, y: 0, width: 400, height: 200)) 32 | //label.backgroundColor = .white 33 | //label.font = UIFont.systemFont(ofSize: 32) 34 | //label.textAlignment = .center 35 | //label.text = "Hello World" 36 | //PlaygroundPage.current.liveView = label 37 | 38 | 39 | let vc = ViewController() 40 | PlaygroundPage.current.liveView = vc 41 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/playground-liveview.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/pointer-memory.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class MyClass { 5 | var a = 1 6 | deinit { 7 | print("deinit") 8 | } 9 | } 10 | 11 | var pointer: UnsafeMutablePointer! 12 | 13 | pointer = UnsafeMutablePointer.allocate(capacity: 1) 14 | pointer.initialize(to: MyClass()) 15 | 16 | print(pointer.pointee.a) 17 | pointer.deinitialize() 18 | pointer.deallocate(capacity: 1) 19 | pointer = nil 20 | 21 | // 输出: 22 | // 1 23 | // deinit 24 | 25 | var x:UnsafeMutablePointer! 26 | var t = time_t() 27 | time(&t) 28 | x = localtime(&t) 29 | x = nil 30 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/pointer-memory.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/print.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class MyClass { 5 | var num: Int 6 | init() { 7 | num = 1 8 | } 9 | } 10 | 11 | let obj = MyClass() 12 | print(obj) 13 | 14 | struct Meeting { 15 | var date: NSDate 16 | var place: String 17 | var attendeeName: String 18 | } 19 | 20 | let meeting = Meeting(date: NSDate(timeIntervalSinceNow: 86400), 21 | place: "会议室B1", 22 | attendeeName: "小明") 23 | print(meeting) 24 | // 输出: 25 | // Meeting(date: 2015-08-10 03:15:55 +0000, place: "会议室B1", attendeeName: "小明") 26 | 27 | extension Meeting: CustomStringConvertible { 28 | var description: String { 29 | return "于 \(self.date) 在 \(self.place) 与 \(self.attendeeName) 进行会议" 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/print.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/property-observer.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class MyClass { 5 | 6 | let oneYearInSecond: TimeInterval = 365 * 24 * 60 * 60 7 | 8 | var date: NSDate { 9 | willSet { 10 | let d = date 11 | print("即将将日期从 \(d) 设定至 \(newValue)") 12 | } 13 | 14 | didSet { 15 | if (date.timeIntervalSinceNow > oneYearInSecond) { 16 | print("设定的时间太晚了!") 17 | date = NSDate().addingTimeInterval(oneYearInSecond) 18 | } 19 | print("已经将日期从 \(oldValue) 设定至 \(date)") 20 | } 21 | } 22 | 23 | init() { 24 | date = NSDate() 25 | } 26 | } 27 | 28 | let foo = MyClass() 29 | foo.date = foo.date.addingTimeInterval(10086) 30 | 31 | // 输出 32 | // 即将将日期从 2014-08-23 12:47:36 +0000 设定至 2014-08-23 15:35:42 +0000 33 | // 已经将日期从 2014-08-23 12:47:36 +0000 设定至 2014-08-23 15:35:42 +0000 34 | 35 | // 365 * 24 * 60 * 60 = 31_536_000 36 | foo.date = foo.date.addingTimeInterval(100_000_000) 37 | 38 | // 输出 39 | // 即将将日期从 2014-08-23 13:24:14 +0000 设定至 2017-10-23 23:10:54 +0000 40 | // 设定的时间太晚了! 41 | // 已经将日期从 2014-08-23 13:24:14 +0000 设定至 2015-08-23 13:24:14 +0000 42 | 43 | class A { 44 | var number :Int { 45 | get { 46 | print("get") 47 | return 1 48 | } 49 | 50 | set {print("set")} 51 | } 52 | } 53 | 54 | class B: A { 55 | override var number: Int { 56 | willSet {print("willSet")} 57 | didSet {print("didSet")} 58 | } 59 | } 60 | 61 | let b = B() 62 | b.number = 0 63 | 64 | // 输出 65 | // get 66 | // willSet 67 | // set 68 | // didSet 69 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/protocol-extension.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | protocol MyProtocol { 5 | func method() 6 | } 7 | 8 | extension MyProtocol { 9 | func method() { 10 | print("Called in extension") 11 | } 12 | } 13 | 14 | //struct MyStruct: MyProtocol { 15 | // 16 | //} 17 | //MyStruct().method() 18 | //// 输出: 19 | //// Called in extension 20 | 21 | struct MyStruct: MyProtocol { 22 | func method() { 23 | print("Called in struct") 24 | } 25 | } 26 | MyStruct().method() 27 | // 输出: 28 | // Called in struct 29 | 30 | protocol A1 { 31 | func method1() -> String 32 | } 33 | 34 | struct B1: A1 { 35 | func method1() -> String { 36 | return "hello" 37 | } 38 | } 39 | 40 | let b1 = B1() 41 | b1.method1() 42 | 43 | let a1: A1 = B1() 44 | a1.method1() 45 | 46 | protocol A2 { 47 | func method1() -> String 48 | } 49 | 50 | extension A2 { 51 | func method1() -> String { 52 | return "hi" 53 | } 54 | 55 | func method2() -> String { 56 | return "hi" 57 | } 58 | } 59 | 60 | struct B2: A2 { 61 | func method1() -> String { 62 | return "hello" 63 | } 64 | 65 | func method2() -> String { 66 | return "hello" 67 | } 68 | } 69 | 70 | let b2 = B2() 71 | 72 | b2.method1() 73 | b2.method2() 74 | 75 | let a2 = b2 as A2 76 | 77 | a2.method1() 78 | 79 | 80 | a2.method2() 81 | 82 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/protocol-extension.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | 49 | 50 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/protocol-mutating.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | protocol Vehicle 5 | { 6 | var numberOfWheels: Int {get} 7 | var color: UIColor {get set} 8 | 9 | mutating func changeColor() 10 | } 11 | 12 | struct MyCar: Vehicle { 13 | let numberOfWheels = 4 14 | var color = UIColor.blue 15 | 16 | mutating func changeColor() { 17 | color = .red 18 | } 19 | } 20 | 21 | var car = MyCar() 22 | car.color 23 | 24 | car.changeColor() 25 | car.color 26 | 27 | 28 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/protocol-mutating.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/random-number.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let diceFaceCount: UInt32 = 6 5 | let randomRoll = Int(arc4random_uniform(diceFaceCount)) + 1 6 | print(randomRoll) 7 | 8 | func random(in range: Range) -> Int { 9 | let count = UInt32(range.upperBound - range.lowerBound) 10 | return Int(arc4random_uniform(count)) + range.lowerBound 11 | } 12 | 13 | for _ in 0...100 { 14 | let range = Range(1...6) 15 | print(random(in: range)) 16 | } 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/range.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | for i in 0...3 { 5 | print(i, terminator: "") 6 | } 7 | //输出 0123 8 | 9 | let test = "helLo" 10 | let interval = "a"..."z" 11 | for c in test.characters { 12 | if !interval.contains(String(c)) { 13 | print("\(c) 不是小写字母") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/range.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/reflect.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | struct Person { 5 | let name: String 6 | let age: Int 7 | } 8 | 9 | let xiaoMing = Person(name: "XiaoMing", age: 16) 10 | let r = Mirror(reflecting: xiaoMing) // r 是 MirrorType 11 | 12 | print("xiaoMing 是 \(r.displayStyle!)") 13 | 14 | print("属性个数:\(r.children.count)") 15 | 16 | for child in r.children { 17 | print("属性名:\(child.label),值:\(child.value)") 18 | } 19 | 20 | //for i in r.children.startIndex.. Any? { 37 | let mirror = Mirror(reflecting: object) 38 | 39 | for child in mirror.children { 40 | let (targetKey, targetMirror) = (child.label, child.value) 41 | if key == targetKey { 42 | return targetMirror 43 | } 44 | } 45 | 46 | return nil 47 | } 48 | 49 | // 接上面的 xiaoMing 50 | if let name = valueFrom(xiaoMing, key: "name") as? String { 51 | print("通过 key 得到值: \(name)") 52 | } 53 | 54 | // 输出: 55 | // 通过 key 得到值: XiaoMing 56 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/reflect.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/regex.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | struct RegexHelper { 5 | let regex: NSRegularExpression 6 | 7 | init(_ pattern: String) throws { 8 | try regex = NSRegularExpression(pattern: pattern, 9 | options: .caseInsensitive) 10 | } 11 | 12 | func match(_ input: String) -> Bool { 13 | let matches = regex.matches(in: input, 14 | options: [], 15 | range: NSMakeRange(0, input.utf16.count)) 16 | return matches.count > 0 17 | } 18 | } 19 | 20 | let mailPattern = 21 | "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$" 22 | 23 | let matcher: RegexHelper 24 | do { 25 | matcher = try RegexHelper(mailPattern) 26 | } 27 | 28 | let maybeMailAddress = "onev@onevcat.com" 29 | 30 | if matcher.match(maybeMailAddress) { 31 | print("有效的邮箱地址") 32 | } 33 | // 输出: 34 | // 有效的邮箱地址 35 | 36 | 37 | precedencegroup MatchPrecedence { 38 | associativity: none 39 | higherThan: DefaultPrecedence 40 | } 41 | 42 | infix operator =~: MatchPrecedence 43 | 44 | func =~(lhs: String, rhs: String) -> Bool { 45 | do { 46 | return try RegexHelper(rhs).match(lhs) 47 | } catch _ { 48 | return false 49 | } 50 | } 51 | 52 | if "onev@onevcat.com" =~ 53 | "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$" { 54 | print("有效的邮箱地址") 55 | } 56 | // 输出: 57 | // 有效的邮箱地址 58 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/selector.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class MyObject: NSObject { 4 | func callMe() { 5 | //... 6 | } 7 | 8 | func callMeWithParam(obj: AnyObject!) { 9 | //... 10 | } 11 | 12 | func turn(by angle: Int, speed: Float) { 13 | //... 14 | } 15 | 16 | func selectors() -> [Selector] { 17 | let someMethod = #selector(callMe) 18 | let anotherMethod = #selector(callMeWithParam(obj:)) 19 | let method = #selector(turn(by:speed:)) 20 | 21 | return [someMethod, anotherMethod, method] 22 | } 23 | 24 | func otherSelectors() -> [Selector] { 25 | let someMethod = #selector(callMe) 26 | let anotherMethod = #selector(callMeWithParam) 27 | let method = #selector(turn) 28 | 29 | return [someMethod, anotherMethod, method] 30 | } 31 | 32 | 33 | func commonFunc() { 34 | 35 | } 36 | 37 | func commonFunc(input: Int) -> Int { 38 | return input 39 | } 40 | 41 | func sameNameSelectors() -> [Selector] { 42 | let method1 = #selector(commonFunc as ()->()) 43 | let method2 = #selector(commonFunc as (Int)->Int) 44 | return [method1, method2] 45 | } 46 | } 47 | 48 | let selectors = MyObject().selectors() 49 | print(selectors) 50 | 51 | let otherSelectors = MyObject().otherSelectors() 52 | print(otherSelectors) 53 | 54 | let sameNameSelectors = MyObject().sameNameSelectors() 55 | print(sameNameSelectors) 56 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/self-anyclass.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | class A { 5 | class func method() { 6 | print("Hello") 7 | } 8 | } 9 | 10 | let typeA: A.Type = A.self 11 | typeA.method() 12 | 13 | // 或者 14 | let anyClass: AnyClass = A.self 15 | (anyClass as! A.Type).method() 16 | 17 | 18 | import UIKit 19 | class MusicViewController: UIViewController { 20 | 21 | } 22 | 23 | class AlbumViewController: UIViewController { 24 | 25 | } 26 | 27 | let usingVCTypes: [AnyClass] = [MusicViewController.self, 28 | AlbumViewController.self] 29 | 30 | func setupViewControllers(_ vcTypes: [AnyClass]) { 31 | for vcType in vcTypes { 32 | if vcType is UIViewController.Type { 33 | let vc = (vcType as! UIViewController.Type).init() 34 | print(vc) 35 | } 36 | 37 | } 38 | } 39 | 40 | setupViewControllers(usingVCTypes) 41 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/self-anyclass.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/sequence.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | // 先定义一个实现了 IteratorProtocol 协议的类型 5 | // IteratorProtocol 需要指定一个 typealias Element 6 | // 以及提供一个返回 Element? 的方法 next() 7 | class ReverseIterator: IteratorProtocol { 8 | typealias Element = T 9 | 10 | var array: [Element] 11 | var currentIndex = 0 12 | 13 | init(array: [Element]) { 14 | self.array = array 15 | currentIndex = array.count - 1 16 | } 17 | 18 | func next() -> Element? { 19 | if currentIndex < 0{ 20 | return nil 21 | } 22 | else { 23 | let element = array[currentIndex] 24 | currentIndex -= 1 25 | return element 26 | } 27 | } 28 | } 29 | 30 | // 然后我们来定义 Sequence 31 | // 和 IteratorProtocol 很类似,不过换成指定一个 typealias Iterator 32 | // 以及提供一个返回 Iterator? 的方法 makeIterator() 33 | struct ReverseSequence: Sequence { 34 | var array: [T] 35 | 36 | init (array: [T]) { 37 | self.array = array 38 | } 39 | 40 | typealias Iterator = ReverseIterator 41 | 42 | func makeIterator() -> ReverseIterator { 43 | return ReverseIterator(array: self.array) 44 | } 45 | } 46 | 47 | let arr = [0,1,2,3,4] 48 | 49 | // 对 Sequence 可以使用 for...in 来循环访问 50 | for i in ReverseSequence(array: arr) { 51 | print("Index \(i) is \(arr[i])") 52 | } 53 | 54 | 55 | var iterator = arr.makeIterator() 56 | while let obj = iterator.next() { 57 | print(obj) 58 | } 59 | 60 | let aaa = ReverseSequence(array: arr) 61 | aaa.map { (Int) -> Int in 62 | return 1 63 | } 64 | 65 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/singleton.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | #if swift(>=3.0) 5 | #else 6 | // This is only for Swift 2.3 and earlier 7 | class MyManager1 { 8 | class var shared : MyManager1 { 9 | struct Static { 10 | static var onceToken : dispatch_once_t = 0 11 | static var staticInstance : MyManager1? = nil 12 | } 13 | 14 | dispatch_once(&Static.onceToken) { 15 | Static.staticInstance = MyManager1() 16 | } 17 | 18 | return Static.staticInstance! 19 | } 20 | } 21 | 22 | MyManager1.shared 23 | 24 | #endif 25 | 26 | class MyManager2 { 27 | private static let sharedInstance = MyManager2() 28 | class var sharedManager : MyManager2 { 29 | return sharedInstance 30 | } 31 | } 32 | 33 | MyManager2.sharedManager 34 | 35 | class MyManager3 { 36 | class var sharedManager : MyManager3 { 37 | return sharedInstance 38 | } 39 | } 40 | private let sharedInstance = MyManager3() 41 | 42 | MyManager3.sharedManager 43 | 44 | class MyManager { 45 | static let sharedManager = MyManager() 46 | private init() {} 47 | } 48 | 49 | MyManager.sharedManager 50 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/singleton.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/static-class.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | struct Point { 5 | let x: Double 6 | let y: Double 7 | 8 | // 存储属性 9 | static let zero = Point(x: 0, y: 0) 10 | 11 | // 计算属性 12 | static var ones: [Point] { 13 | return [Point(x: 1, y: 1), 14 | Point(x: -1, y: 1), 15 | Point(x: 1, y: -1), 16 | Point(x: -1, y: -1)] 17 | } 18 | 19 | // 类型方法 20 | static func add(p1: Point, p2: Point) -> Point { 21 | return Point(x: p1.x + p2.x, y: p1.y + p2.y) 22 | } 23 | } 24 | 25 | Point.zero 26 | 27 | Point.ones 28 | 29 | Point.add(p1: Point.zero, p2: Point.ones.first!) 30 | 31 | class MyClass1 { 32 | static var bar: String? 33 | } 34 | 35 | protocol MyProtocol { 36 | static func foo() -> String 37 | } 38 | 39 | struct MyStruct: MyProtocol { 40 | static func foo() -> String { 41 | return "MyStruct" 42 | } 43 | } 44 | 45 | enum MyEnum: MyProtocol { 46 | static func foo() -> String { 47 | return "MyEnum" 48 | } 49 | } 50 | 51 | class MyClass: MyProtocol { 52 | // 在 class 中可以使用 class 53 | class func foo() -> String { 54 | return "MyClass.foo()" 55 | } 56 | 57 | // 也可以使用 static 58 | static func bar() -> String { 59 | return "MyClass.bar()" 60 | } 61 | } 62 | 63 | MyClass.foo() 64 | MyClass.bar() 65 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/static-class.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/string-nsstring.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let levels = "ABCDE" 5 | for i in levels.characters { 6 | print(i) 7 | } 8 | 9 | // 输出: 10 | // ABCDE 11 | if (levels as NSString).contains("BC") { 12 | print("包含字符串") 13 | } 14 | 15 | levels.contains("") 16 | 17 | 18 | // 输出: 19 | // 包含字符串 20 | 21 | 22 | let nsRange = NSMakeRange(1, 4) 23 | // 编译错误 24 | // Cannot convert value of type `NSRanve` to expected argument type 'Range' 25 | //levels.replacingCharacters(in: nsRange, with: "AAAA") 26 | 27 | let indexPositionOne = levels.characters.index(levels.startIndex, offsetBy: 1) 28 | let swiftRange = indexPositionOne ..< levels.characters.index(levels.startIndex, offsetBy: 5) 29 | levels.replacingCharacters(in: swiftRange, with: "AAAA") 30 | // 输出: 31 | // AAAAA 32 | 33 | (levels as NSString).replacingCharacters(in: nsRange, with: "AAAA") 34 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/struct-mutating.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /* Wrong code 5 | struct User { 6 | var age : Int 7 | var weight : Int 8 | var height : Int 9 | 10 | func gainWeight(newWeight: Int) { 11 | weight += newWeight 12 | } 13 | } 14 | */ 15 | 16 | struct User { 17 | var age : Int 18 | var weight : Int 19 | var height : Int 20 | 21 | mutating func gainWeight(newWeight: Int) { 22 | weight += newWeight 23 | } 24 | } 25 | 26 | var u = User(age: 1, weight: 1, height: 1) 27 | u.gainWeight(newWeight: 2) 28 | u 29 | 30 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/struct-mutating.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/subscript.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | var arr = [1,2,3] 5 | arr[2] // 3 6 | arr[2] = 4 // arr = [1,2,4] 7 | 8 | var dic = ["cat":"meow", "goat":"mie"] 9 | dic["cat"] // {Some "meow"} 10 | dic["cat"] = "miao" // dic = ["cat":"miao", "goat":"mie"] 11 | 12 | extension Array { 13 | subscript(input: [Int]) -> ArraySlice { 14 | get { 15 | var result = ArraySlice() 16 | for i in input { 17 | assert(i < self.count, "Index out of range") 18 | result.append(self[i]) 19 | } 20 | return result 21 | } 22 | 23 | set { 24 | for (index,i) in input.enumerated() { 25 | assert(i < self.count, "Index out of range") 26 | self[i] = newValue[index] 27 | } 28 | } 29 | } 30 | } 31 | 32 | arr = [1,2,3,4,5] 33 | arr[[0,2,3]] //[1,3,4] 34 | arr[[0,2,3]] = [-1,-3,-4] 35 | arr //[-1,2,-3,-4,5] 36 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/subscript.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/tail-recursion.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func sum(_ n: UInt) -> UInt { 5 | if n == 0 { 6 | return 0 7 | } 8 | return n + sum(n - 1) 9 | } 10 | 11 | sum(4) 12 | sum(100) 13 | 14 | 15 | func tailSum(_ n: UInt) -> UInt { 16 | func sumInternal(_ n: UInt, current: UInt) -> UInt { 17 | if n == 0 { 18 | return current 19 | } else { 20 | return sumInternal(n - 1, current: current + n) 21 | } 22 | } 23 | 24 | return sumInternal(n, current: 0) 25 | } 26 | 27 | // 两者在 Playground 中都会崩溃。 28 | // 请在实际项目中的 Release build 下尝试 29 | //sum(1000000) 30 | //tailSum(1000000) 31 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/tail-recursion.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/toll-free.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import AudioToolbox 4 | 5 | let fileURL = NSURL(string: "SomeURL") 6 | var theSoundID: SystemSoundID = 0 7 | AudioServicesCreateSystemSoundID(fileURL!, &theSoundID) 8 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/toll-free.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/tuple.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | func swapMe1( a: inout T, b: inout T) { 5 | let temp = a 6 | a = b 7 | b = temp 8 | } 9 | 10 | func swapMe2( a: inout T, b: inout T) { 11 | (a,b) = (b,a) 12 | } 13 | 14 | var a = 1 15 | var b = 2 16 | 17 | (a, b) 18 | swapMe1(a: &a, b: &b) 19 | (a, b) 20 | 21 | 22 | swapMe2(a: &a, b: &b) 23 | (a, b) 24 | 25 | let rect = CGRect(x: 0, y: 0, width: 100, height: 100) 26 | 27 | let (small, large) = rect.divided(atDistance: 20, from: .minXEdge) 28 | 29 | small 30 | large 31 | 32 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/tuple.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/type-encode.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | let int: Int = 0 5 | let float: Float = 0.0 6 | let double: Double = 0.0 7 | 8 | let intNumber: NSNumber = int as NSNumber 9 | let floatNumber: NSNumber = float as NSNumber 10 | let doubleNumber: NSNumber = double as NSNumber 11 | 12 | String(validatingUTF8: intNumber.objCType) 13 | String(validatingUTF8: floatNumber.objCType) 14 | String(validatingUTF8: doubleNumber.objCType) 15 | 16 | // 结果分别为: 17 | // {Some "q"} 18 | // {Some "f"} 19 | // {Some "d"} 20 | // 注意,fromCString 返回的是 `String?` 21 | 22 | 23 | 24 | 25 | let p = NSValue(cgPoint: CGPoint(x: 3, y: 3)) 26 | String(validatingUTF8: p.objCType) 27 | // {Some "{CGPoint=dd}"} 28 | 29 | let t = NSValue(cgAffineTransform: .identity) 30 | String(validatingUTF8: t.objCType) 31 | // {Some "{CGAffineTransform=dddddd}"} 32 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/type-encode.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/typealias.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | typealias Location = CGPoint 5 | typealias Distance = Double 6 | 7 | func distance(from location: Location, 8 | to anotherLocation: Location) -> Distance { 9 | let dx = Distance(location.x - anotherLocation.x) 10 | let dy = Distance(location.y - anotherLocation.y) 11 | return sqrt(dx * dx + dy * dy) 12 | } 13 | 14 | let origin: Location = Location(x: 0, y: 0) 15 | let point: Location = Location(x: 1, y: 1) 16 | 17 | let d = distance(from: origin, to: point) 18 | 19 | class Person {} 20 | 21 | typealias WorkId = String 22 | typealias Worker = Person 23 | 24 | //class Person {} 25 | 26 | typealias WorkerGeneric = Person 27 | 28 | let w1 = Worker() 29 | let w2 = WorkerGeneric() 30 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/unsafe.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func method(_ num: UnsafePointer) { 5 | print(num.pointee) 6 | } 7 | 8 | // Swift 9 | var a: CInt = 123 10 | method(&a) // 输出 123 11 | 12 | let arr = NSArray(object: "meow") 13 | let str = unsafeBitCast(CFArrayGetValueAtIndex(arr, 0), to: CFString.self) 14 | // str = "meow" 15 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/unsafe.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/use-self.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | protocol Copyable { 5 | func copy() -> Self 6 | } 7 | 8 | class MyClass: Copyable { 9 | 10 | var num = 1 11 | 12 | func copy() -> Self { 13 | let result = type(of: self).init() 14 | result.num = num 15 | return result 16 | } 17 | 18 | required init() { 19 | 20 | } 21 | } 22 | 23 | let object = MyClass() 24 | object.num = 100 25 | 26 | let newObject = object.copy() 27 | object.num = 1 28 | 29 | print(object.num) // 1 30 | print(newObject.num) // 100 31 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/use-self.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/value-reference.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func test(_ arr: [Int]) { 5 | for i in arr { 6 | print(i) 7 | } 8 | } 9 | 10 | var a1 = [1,2,3] 11 | var b1 = a1 12 | let c1 = b1 13 | test(a1) 14 | 15 | var a2 = [1,2,3] 16 | var b2 = a2 17 | b2.append(5) 18 | // 此时 a 和 b 的内存地址不再相同 19 | 20 | class MyObject { 21 | var num = 0 22 | } 23 | 24 | var myObject = MyObject() 25 | var a3 = [myObject] 26 | var b3 = a3 27 | 28 | b3.append(myObject) 29 | 30 | myObject.num = 100 31 | print(b3[0].num) //100 32 | print(b3[1].num) //100 33 | 34 | // myObject 的改动同时影响了 b3[0] 和 b3[1] 35 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/variadic.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | func sum(input: Int...) -> Int { 5 | return input.reduce(0, +) 6 | } 7 | 8 | print(sum(input: 1,2,3,4,5)) 9 | // 输出:15 10 | 11 | func myFunc(numbers: Int..., string: String) { 12 | numbers.forEach { 13 | for i in 0..<$0 { 14 | print("\(i + 1): \(string)") 15 | } 16 | } 17 | } 18 | 19 | myFunc(numbers: 1, 2, 3, string: "hello") 20 | 21 | 22 | 23 | let name = "Tom" 24 | let date = NSDate() 25 | let string = NSString(format: "Hello %@. Date: %@", name, date) 26 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/variadic.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/where.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | let name = ["王小二","张三","李四","王二小"] 5 | 6 | name.forEach { 7 | switch $0 { 8 | case let x where x.hasPrefix("王"): 9 | print("\(x)是笔者本家") 10 | default: 11 | print("你好,\($0)") 12 | } 13 | } 14 | 15 | // 输出: 16 | // 王小二是笔者本家 17 | // 你好,张三 18 | // 你好,李四 19 | // 王二小是笔者本家 20 | 21 | let num: [Int?] = [48, 99, nil] 22 | 23 | let n = num.flatMap {$0} 24 | for score in n where score > 60 { 25 | print("及格啦 - \(score)") 26 | } 27 | // 输出: 28 | // 及格啦 - Optional(99) 29 | 30 | num.forEach { 31 | if let score = $0, score > 60 { 32 | print("及格啦 - \(score)") 33 | } else { 34 | print(":(") 35 | } 36 | } 37 | // 输出: 38 | // :( 39 | // 及格啦 - 99 40 | // :( 41 | 42 | let sortableArray: [Int] = [3,1,2,4,5] 43 | let unsortableArray: [Any?] = ["Hello", 4, nil] 44 | 45 | sortableArray.sorted() 46 | 47 | //unsortableArray.sorted() 48 | 49 | -------------------------------------------------------------------------------- /Swifter.playground/Pages/where.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Swifter.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /Swifter.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Swifter.playground/playground.xcworkspace/xcshareddata/Swifter.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "7502F96F5C4E53E5E4D8F6D0CE6682F7FD5510AE", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "7502F96F5C4E53E5E4D8F6D0CE6682F7FD5510AE" : 0, 8 | "C06821B1F3517FF3FE504C9E5AB8525DE79DEFEF" : 0 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "73A4433D-12C5-4FD5-982D-850CC97BED98", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "7502F96F5C4E53E5E4D8F6D0CE6682F7FD5510AE" : "playground\/", 13 | "C06821B1F3517FF3FE504C9E5AB8525DE79DEFEF" : "" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "Swifter", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Swifter.playground", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:swifter-tips\/Playground.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "7502F96F5C4E53E5E4D8F6D0CE6682F7FD5510AE" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "gitlab.com:onevcat\/swifter.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "C06821B1F3517FF3FE504C9E5AB8525DE79DEFEF" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /Swifter.playground/playground.xcworkspace/xcuserdata/JP20028.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swifter-tips/Playground/3d841ad3f9cf530dc925e65ba1f52c003b8b572d/Swifter.playground/playground.xcworkspace/xcuserdata/JP20028.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Swifter.playground/playground.xcworkspace/xcuserdata/JP20028.xcuserdatad/userinterfacestate (Wei Wang の競合コピー 2016-09-07).xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swifter-tips/Playground/3d841ad3f9cf530dc925e65ba1f52c003b8b572d/Swifter.playground/playground.xcworkspace/xcuserdata/JP20028.xcuserdatad/userinterfacestate (Wei Wang の競合コピー 2016-09-07).xcuserstate -------------------------------------------------------------------------------- /Swifter.playground/playground.xcworkspace/xcuserdata/onevcat.xcuserdatad/UserInterfaceState (Wei Wang の競合コピー 2016-09-07).xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swifter-tips/Playground/3d841ad3f9cf530dc925e65ba1f52c003b8b572d/Swifter.playground/playground.xcworkspace/xcuserdata/onevcat.xcuserdatad/UserInterfaceState (Wei Wang の競合コピー 2016-09-07).xcuserstate -------------------------------------------------------------------------------- /Swifter.playground/playground.xcworkspace/xcuserdata/onevcat.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swifter-tips/Playground/3d841ad3f9cf530dc925e65ba1f52c003b8b572d/Swifter.playground/playground.xcworkspace/xcuserdata/onevcat.xcuserdatad/UserInterfaceState.xcuserstate --------------------------------------------------------------------------------