├── combineOperators ├── combineOperators.playground │ ├── Contents.swift │ ├── timeline.xctimeline │ ├── playground.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── ganesh.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ ├── contents.xcplayground │ └── xcuserdata │ │ └── ganesh.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── CombineOperators.png ├── README.md ├── Combining Operators └── MyPlayground.playground │ ├── Sources │ └── Helper.swift │ ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── ganesh.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── contents.xcplayground │ └── Contents.swift ├── Filtering Operators └── MyPlayground.playground │ ├── Sources │ └── Helper.swift │ ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── ganesh.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── contents.xcplayground │ └── Contents.swift ├── Publisher&Subscriber └── MyPlayground.playground │ ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── ganesh.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── contents.xcplayground │ ├── Sources │ └── Helper.swift │ └── Contents.swift ├── Transforming_Operators └── MyPlayground.playground │ ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── ganesh.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── contents.xcplayground │ ├── Sources │ └── Helper.swift │ └── Contents.swift └── LinkedInLearning.swift /combineOperators/combineOperators.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | var greeting = "Hello, playground" 4 | -------------------------------------------------------------------------------- /combineOperators/CombineOperators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaneshRajuGalla/Combine/HEAD/combineOperators/CombineOperators.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # combineOperators 2 | 3 | ![](https://github.com/GaneshRajuGalla/combineOperators/blob/main/combineOperators/CombineOperators.png) 4 | -------------------------------------------------------------------------------- /combineOperators/combineOperators.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Combining Operators/MyPlayground.playground/Sources/Helper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func example(of description:String,action: () -> Void){ 4 | print("\n——— Example of:", description, "———") 5 | action() 6 | } 7 | -------------------------------------------------------------------------------- /Filtering Operators/MyPlayground.playground/Sources/Helper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func example(of description:String,action: () -> Void){ 4 | print("\n——— Example of:", description, "———") 5 | action() 6 | } 7 | -------------------------------------------------------------------------------- /Combining Operators/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Filtering Operators/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Publisher&Subscriber/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Transforming_Operators/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /combineOperators/combineOperators.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Combining Operators/MyPlayground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Filtering Operators/MyPlayground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Publisher&Subscriber/MyPlayground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Transforming_Operators/MyPlayground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Combining Operators/MyPlayground.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaneshRajuGalla/Combine/HEAD/Combining Operators/MyPlayground.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Filtering Operators/MyPlayground.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaneshRajuGalla/Combine/HEAD/Filtering Operators/MyPlayground.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Publisher&Subscriber/MyPlayground.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaneshRajuGalla/Combine/HEAD/Publisher&Subscriber/MyPlayground.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /combineOperators/combineOperators.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaneshRajuGalla/Combine/HEAD/combineOperators/combineOperators.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Transforming_Operators/MyPlayground.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GaneshRajuGalla/Combine/HEAD/Transforming_Operators/MyPlayground.playground/playground.xcworkspace/xcuserdata/ganesh.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /combineOperators/combineOperators.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /combineOperators/combineOperators.playground/xcuserdata/ganesh.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | combineOperators (Playground).xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 0 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Transforming_Operators/MyPlayground.playground/Sources/Helper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | public func example(of description:String,action: () -> Void){ 5 | print("\n——— Example of:", description, "———") 6 | action() 7 | } 8 | 9 | public struct Coordinate { 10 | public let x: Int 11 | public let y: Int 12 | 13 | public init(x: Int, y: Int) { 14 | self.x = x 15 | self.y = y 16 | } 17 | } 18 | 19 | public func quadrantOf(x: Int, y: Int) -> String { 20 | var quadrant = "" 21 | 22 | switch (x, y) { 23 | case (1..., 1...): 24 | quadrant = "1" 25 | case (..<0, 1...): 26 | quadrant = "2" 27 | case (..<0, ..<0): 28 | quadrant = "3" 29 | case (1..., ..<0): 30 | quadrant = "4" 31 | default: 32 | quadrant = "boundary" 33 | } 34 | 35 | return quadrant 36 | } 37 | -------------------------------------------------------------------------------- /Publisher&Subscriber/MyPlayground.playground/Sources/Helper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func example(of description:String,action: () -> ()){ 4 | print("\n——— Example of:", description, "———") 5 | action() 6 | print() 7 | } 8 | 9 | 10 | public let cards = [ 11 | ("🂡", 11), ("🂢", 2), ("🂣", 3), ("🂤", 4), ("🂥", 5), ("🂦", 6), ("🂧", 7), ("🂨", 8), ("🂩", 9), ("🂪", 10), ("🂫", 10), ("🂭", 10), ("🂮", 10), 12 | ("🂱", 11), ("🂲", 2), ("🂳", 3), ("🂴", 4), ("🂵", 5), ("🂶", 6), ("🂷", 7), ("🂸", 8), ("🂹", 9), ("🂺", 10), ("🂻", 10), ("🂽", 10), ("🂾", 10), 13 | ("🃁", 11), ("🃂", 2), ("🃃", 3), ("🃄", 4), ("🃅", 5), ("🃆", 6), ("🃇", 7), ("🃈", 8), ("🃉", 9), ("🃊", 10), ("🃋", 10), ("🃍", 10), ("🃎", 10), 14 | ("🃑", 11), ("🃒", 2), ("🃓", 3), ("🃔", 4), ("🃕", 5), ("🃖", 6), ("🃗", 7), ("🃘", 8), ("🃙", 9), ("🃚", 10), ("🃛", 10), ("🃝", 10), ("🃞", 10) 15 | ] 16 | 17 | 18 | public typealias Card = (String,Int) 19 | public typealias Hand = [Card] 20 | 21 | public extension Hand{ 22 | var cardString:String{ 23 | map{$0.0}.joined() 24 | } 25 | 26 | var points:Int{ 27 | map{$0.1}.reduce(0, +) 28 | } 29 | } 30 | 31 | public enum HandError:Error,CustomStringConvertible{ 32 | case busted 33 | 34 | public var description:String{ 35 | switch self { 36 | case .busted: 37 | return "Busted!" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LinkedInLearning.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Combine 3 | 4 | 5 | let notification = Notification(name: .NSSystemClockDidChange,object: nil,userInfo: nil) 6 | let clockNotification = NotificationCenter.default.publisher(for: .NSSystemClockDidChange) 7 | .sink(receiveValue: {(value) in 8 | print("Value is \(value)") 9 | }) 10 | NotificationCenter.default.post(notification) 11 | 12 | let _ = Just("Hello World") 13 | .sink{(value) in 14 | print("Value is \(value)") 15 | } 16 | 17 | [1,5,9] 18 | .publisher 19 | .map{$0 * $0} 20 | .sink{print($0)} 21 | 22 | 23 | let url = URL(string: "https://jsonplaceholder.typicode.com/posts")! 24 | 25 | struct Task:Decodable{ 26 | let id:Int 27 | let title:String 28 | let userId:Int 29 | let body:String 30 | } 31 | 32 | 33 | let dataPublisher = URLSession.shared.dataTaskPublisher(for: url) 34 | .map{$0.data} 35 | .decode(type: [Task].self, decoder: JSONDecoder()) 36 | 37 | let cancellableSink = dataPublisher 38 | .sink(receiveCompletion: {completion in 39 | print(completion) 40 | }, receiveValue: {itmes in 41 | print("Result \(itmes[0].title)") 42 | }) 43 | 44 | // MARK: Assign 45 | let lable = UILabel() 46 | Just("Ganesh") 47 | .map{"My Name is \($0)"} 48 | .assign(to: \.text, on: lable) 49 | 50 | //(1) Declare an Int PassthroughSubject 51 | let subject = PassthroughSubject() 52 | //(2) Attch a subscriber to subject 53 | let subscription = subject 54 | .sink{print($0)} 55 | //(3) Publish the value '94' via the subject,directlt 56 | subject.send(94) 57 | //(4) Connect subject to a publisher,and publish the value '29' 58 | Just(29) 59 | .subscribe(subject) 60 | //(5) Declare Another subject, a CurrentvalueSubject, with an initial "I am a value cached" 61 | let anotherSubjcet = CurrentValueSubject("I am a...") 62 | //(6) Attach a subscriber to the subject 63 | let anothersubscriber = anotherSubjcet 64 | .sink{print($0)} 65 | //(7) Publish a value "Subjcet" via the subject directly 66 | anotherSubjcet.send("Subject") 67 | 68 | // Simple use of Future in a Function 69 | enum FutureError:Error{ 70 | case notMultiple 71 | } 72 | 73 | let future = Future{ promise in 74 | let calender = Calendar.current 75 | let second = calender.component(.second, from: Date()) 76 | print("Seconds is : \(second)") 77 | if second.isMultiple(of: 3){ 78 | promise(.success("We are successful:\(second)")) 79 | }else{ 80 | promise(.failure(.notMultiple)) 81 | } 82 | }.catch{error in 83 | Just("Caught the error") 84 | } 85 | .delay(for: .init(1), scheduler: RunLoop.main) 86 | .eraseToAnyPublisher() 87 | 88 | future.sink(receiveCompletion: {print($0)}, receiveValue: {print($0)}) 89 | 90 | 91 | // Challenge 92 | let textField = UITextField() 93 | let array = [true,false,true,false,false,false,true,true] 94 | let publisher = array.publisher 95 | let subscriber = publisher.assign(to: \.isEnabled, on: textField) 96 | textField.publisher(for: \.isEnabled).sink{print($0)} 97 | let _ = publisher.dropFirst(2).sink{print($0)} 98 | -------------------------------------------------------------------------------- /Transforming_Operators/MyPlayground.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Combine 3 | 4 | 5 | var subscriptions = Set() 6 | 7 | //collect() 8 | example(of: "collect") { 9 | ["A","B","C","D","E","F"].publisher 10 | .collect(2) 11 | .sink(receiveCompletion: {print($0)}, receiveValue: {print($0)}) 12 | .store(in: &subscriptions) 13 | } 14 | 15 | // Mapping values 16 | example(of: "map") { 17 | let formatter = NumberFormatter() 18 | formatter.numberStyle = .spellOut 19 | 20 | [123,4,5].publisher 21 | .map{ 22 | formatter.string(for: NSNumber(integerLiteral: $0)) ?? "" 23 | } 24 | .sink(receiveValue: {print($0)}) 25 | .store(in: &subscriptions) 26 | } 27 | 28 | // map key paths 29 | example(of: "map key paths") { 30 | let publisher = PassthroughSubject() 31 | 32 | publisher 33 | .map(\.x,\.y) 34 | .sink(receiveValue: { x,y in 35 | print("The coordinate at (\(x), \(y)) is in quadrant", quadrantOf(x: x, y: y)) 36 | }) 37 | .store(in: &subscriptions) 38 | publisher.send(Coordinate(x: 10, y: -8)) 39 | publisher.send(Coordinate(x: 0, y: 5)) 40 | } 41 | 42 | //tryMap(_:) 43 | example(of: "tryMap") { 44 | Just("Directory name that does not exist") 45 | .tryMap { try FileManager.default.contentsOfDirectory(atPath: $0)} 46 | .sink(receiveCompletion: {print($0)}, receiveValue: {print($0)}) 47 | .store(in: &subscriptions) 48 | } 49 | 50 | //Flattening publishers 51 | example(of: "flatMap") { 52 | func decode(_ codes: [Int]) -> AnyPublisher { 53 | Just( 54 | codes 55 | .compactMap { code in 56 | guard (32...255).contains(code) else { return nil } 57 | return String(UnicodeScalar(code) ?? " ") 58 | } 59 | .joined() 60 | ) 61 | .eraseToAnyPublisher() 62 | } 63 | 64 | [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33] 65 | .publisher 66 | .collect() 67 | .flatMap(decode) 68 | .collect() 69 | .map { $0.joined() } 70 | .sink(receiveValue: { print($0) }) 71 | .store(in: &subscriptions) 72 | } 73 | 74 | //replaceNil 75 | example(of: "replaceNil") { 76 | ["A",nil,"C"].publisher 77 | .eraseToAnyPublisher() 78 | .replaceNil(with: "_" as String?) 79 | .sink(receiveValue: {print($0)}) 80 | .store(in: &subscriptions) 81 | } 82 | 83 | //replaceEmpty(with:) 84 | example(of: "replaceEmpty(with:)") { 85 | let empty = Empty() 86 | empty 87 | .sink(receiveCompletion: {print($0)}, receiveValue: {print($0)}) 88 | .store(in: &subscriptions) 89 | } 90 | 91 | example(of: "scan") { 92 | var dailyGainloss:Int { 93 | .random(in: -10...10) 94 | } 95 | 96 | let august2019 = (0..<22) 97 | .map{_ in dailyGainloss} 98 | .publisher 99 | 100 | august2019 101 | .scan(50) { latest, current in 102 | max(0,latest+current) 103 | } 104 | .sink(receiveValue: {_ in}) 105 | .store(in: &subscriptions) 106 | } 107 | 108 | //Challenge 109 | example(of: "Create phone number lookup") { 110 | let contacts = [ 111 | "603-555-1234": "Florent", 112 | "408-555-4321": "Marin", 113 | "217-555-1212": "Scott", 114 | "212-555-3434": "Shai" 115 | ] 116 | 117 | func convert(phoneNumber:String) -> Int?{ 118 | if let number = Int(phoneNumber),number < 10{ 119 | return number 120 | } 121 | 122 | let keyMap: [String: Int] = [ 123 | "abc": 2, "def": 3, "ghi": 4, 124 | "jkl": 5, "mno": 6, "pqrs": 7, 125 | "tuv": 8, "wxyz": 9 126 | ] 127 | 128 | let converted = keyMap 129 | .filter{$0.key.contains(phoneNumber.lowercased())} 130 | .map{$0.value} 131 | .first 132 | 133 | return converted 134 | } 135 | 136 | func format(digits: [Int]) -> String { 137 | var phone = digits.map(String.init) 138 | .joined() 139 | 140 | phone.insert("-", at: phone.index( 141 | phone.startIndex, 142 | offsetBy: 3) 143 | ) 144 | 145 | phone.insert("-", at: phone.index( 146 | phone.startIndex, 147 | offsetBy: 7) 148 | ) 149 | return phone 150 | } 151 | 152 | func dial(phoneNumber:String) -> String{ 153 | guard let contact = contacts[phoneNumber] else { 154 | return "Contact not fount \(phoneNumber)" 155 | } 156 | 157 | return "Dialing \(contact) (\(phoneNumber))..." 158 | } 159 | 160 | let input = PassthroughSubject() 161 | input 162 | .map(convert) 163 | .replaceNil(with: 0) 164 | .collect(10) 165 | .map(format) 166 | .map(dial) 167 | .sink(receiveValue: {print($0)}) 168 | .store(in: &subscriptions) 169 | 170 | "0!1234567".forEach { 171 | input.send(String($0)) 172 | } 173 | 174 | "4085554321".forEach { 175 | input.send(String($0)) 176 | } 177 | 178 | "A1BJKLDGEH".forEach { 179 | input.send("\($0)") 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /Filtering Operators/MyPlayground.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Combine 3 | 4 | 5 | var subscription = Set() 6 | 7 | //Filter 8 | example(of: "filter") { 9 | let numbers = (1...10).publisher 10 | 11 | numbers 12 | .filter { $0.isMultiple(of: 3)} 13 | .sink(receiveValue: { n in 14 | print("\(n) is multiple of 3") 15 | }) 16 | .store(in: &subscription) 17 | } 18 | 19 | 20 | //removeDuplicates 21 | example(of: "removeDuplicates") { 22 | let words = "hey hey there! want to listen to mister mister ?".components(separatedBy: " ").publisher 23 | 24 | words 25 | .removeDuplicates() 26 | .sink(receiveValue: {print($0)}) 27 | .store(in: &subscription) 28 | } 29 | 30 | //compactMap 31 | example(of: "compactMap") { 32 | let strings = ["a", "1.24", "3","def", "45", "0.23"].publisher 33 | 34 | strings 35 | .compactMap { Float($0)} 36 | .sink(receiveValue: {print($0)}) 37 | .store(in: &subscription) 38 | } 39 | 40 | //ignoreOutput 41 | example(of: "ignoreOutput") { 42 | let numbers = (1...10_000).publisher 43 | 44 | numbers 45 | .ignoreOutput() 46 | .sink(receiveCompletion: {print("Completed with \($0)")}, receiveValue: {print($0)}) 47 | .store(in: &subscription) 48 | } 49 | 50 | 51 | //first(where:) 52 | example(of: "first(where:)") { 53 | let numbers = (1...9).publisher 54 | 55 | numbers 56 | .print("numbers") 57 | .first(where: {$0 % 2 == 0}) 58 | .sink(receiveCompletion: {print("Completed with \($0)")}, receiveValue: {print($0)}) 59 | .store(in: &subscription) 60 | } 61 | 62 | 63 | //last(where:) 64 | example(of: "last(where:)") { 65 | let numbers = (1...9).publisher 66 | 67 | numbers 68 | .print("numbers") 69 | .last(where: {$0 % 2 == 0}) 70 | .sink(receiveCompletion: {print("Completion with \($0)")}, receiveValue: {print($0)}) 71 | .store(in: &subscription) 72 | } 73 | 74 | example(of: "last(where:)") { 75 | let numbers = PassthroughSubject() 76 | 77 | numbers 78 | .last(where: {$0 % 2 == 0}) 79 | .sink(receiveCompletion: {print("Completion with \($0)")}, receiveValue: {print($0)}) 80 | .store(in: &subscription) 81 | 82 | numbers.send(1) 83 | numbers.send(2) 84 | numbers.send(3) 85 | numbers.send(4) 86 | numbers.send(5) 87 | numbers.send(completion: .finished) 88 | } 89 | 90 | //dropFirst 91 | example(of: "dropFirst") { 92 | let numbers = (1...10).publisher 93 | 94 | numbers 95 | .dropFirst(5) 96 | .sink(receiveValue: {print($0)}) 97 | .store(in: &subscription) 98 | } 99 | 100 | //drop(while: 101 | example(of: "drop(while:)") { 102 | let numbers = (1...10).publisher 103 | 104 | numbers 105 | .drop(while: {$0%5 != 0}) 106 | .sink(receiveValue: {print($0)}) 107 | .store(in: &subscription) 108 | } 109 | 110 | example(of: "drop(while:)") { 111 | let numbers = (1...10).publisher 112 | 113 | numbers 114 | .drop(while: { 115 | print("x") 116 | return $0 % 5 != 0 117 | }) 118 | .sink(receiveValue: {print($0)}) 119 | .store(in: &subscription) 120 | } 121 | 122 | //drop(untilOutputFrom:) 123 | example(of: "drop(untilOutputFrom:)") { 124 | let isReady = PassthroughSubject() 125 | let taps = PassthroughSubject() 126 | 127 | taps 128 | .drop(untilOutputFrom: isReady) 129 | .sink(receiveValue: {print($0)}) 130 | .store(in: &subscription) 131 | 132 | (1...10).forEach{ n in 133 | taps.send(n) 134 | 135 | if n == 3{ 136 | isReady.send() 137 | } 138 | } 139 | } 140 | 141 | 142 | //prefix 143 | example(of: "prefix") { 144 | let numbers = (1...10).publisher 145 | 146 | numbers 147 | .prefix(2) 148 | .sink(receiveCompletion: {print("Recieved with completion \($0)")}, receiveValue: {print($0)}) 149 | .store(in: &subscription) 150 | } 151 | 152 | //prefix(while:) 153 | 154 | example(of: "prefix(while:)") { 155 | let numbers = (1...10).publisher 156 | 157 | numbers 158 | .prefix(while: {$0 < 3}) 159 | .sink(receiveCompletion: {print("Recieved with completion \($0)")}, receiveValue: {print($0)}) 160 | .store(in: &subscription) 161 | } 162 | 163 | //prefix(untilOutputFrom:) 164 | example(of: "prefix(untilOutputFrom:)") { 165 | let isReady = PassthroughSubject() 166 | let taps = PassthroughSubject() 167 | 168 | taps 169 | .prefix(untilOutputFrom: isReady) 170 | .sink(receiveValue: {print($0)}) 171 | .store(in: &subscription) 172 | 173 | (1...10).forEach{ n in 174 | taps.send(n) 175 | 176 | if n == 3{ 177 | isReady.send() 178 | } 179 | } 180 | } 181 | 182 | // Challenge 183 | 184 | example(of: "Challenge") { 185 | let numbers = (1...100).publisher 186 | 187 | numbers 188 | .dropFirst(50) 189 | .prefix(20) 190 | .filter{$0 % 2 == 0} 191 | .sink(receiveValue: {print($0)}) 192 | .store(in: &subscription) 193 | } 194 | -------------------------------------------------------------------------------- /Combining Operators/MyPlayground.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Combine 3 | 4 | var subscriptions = Set() 5 | 6 | //MARK: - Combining Operators 7 | 8 | //Prepending 9 | 10 | //prepend(Output...) 11 | example(of: "prepend(Output...)") { 12 | let publisher = [3,4].publisher 13 | 14 | publisher 15 | .prepend(1,2) 16 | .prepend(-1,0) 17 | .sink(receiveValue: {print($0)}) 18 | .store(in: &subscriptions) 19 | } 20 | 21 | //prepend(Sequence) 22 | example(of: "prepend(Sequence)") { 23 | let publisher = [5,6,7].publisher 24 | 25 | publisher 26 | .prepend([3,4]) 27 | .prepend(Set(1...2)) 28 | .prepend(stride(from: 6, through: 11, by: 2)) 29 | .sink(receiveValue: {print($0)}) 30 | .store(in: &subscriptions) 31 | } 32 | 33 | //prepend(Publisher) 34 | example(of: "prepend(Publisher)") { 35 | let publisher1 = [3,4].publisher 36 | let publisher2 = [1,2].publisher 37 | 38 | publisher1 39 | .prepend(publisher2) 40 | .sink(receiveValue: {print($0)}) 41 | .store(in: &subscriptions) 42 | } 43 | 44 | //prepend(Publisher) #2 45 | example(of: "prepend(Publisher) #2") { 46 | let publisher1 = [3,4].publisher 47 | let publisher2 = PassthroughSubject() 48 | 49 | publisher1 50 | .prepend(publisher2) 51 | .sink(receiveValue: {print($0)}) 52 | .store(in: &subscriptions) 53 | 54 | publisher2.send(1) 55 | publisher2.send(2) 56 | publisher2.send(completion: .finished) 57 | } 58 | 59 | //Appending 60 | //append(Output...) 61 | example(of: "append(Output...)") { 62 | let publisher = [1].publisher 63 | 64 | publisher 65 | .append(2,3) 66 | .append(4) 67 | .sink(receiveValue: {print($0)}) 68 | .store(in: &subscriptions) 69 | } 70 | 71 | example(of: "append(Output...) #2") { 72 | let publisher = PassthroughSubject() 73 | 74 | publisher 75 | .append(3,4) 76 | .append(5) 77 | .sink(receiveValue: {print($0)}) 78 | .store(in: &subscriptions) 79 | 80 | publisher.send(1) 81 | publisher.send(2) 82 | publisher.send(completion: .finished) 83 | } 84 | 85 | //append(Sequence) 86 | example(of: "append(Sequence)") { 87 | let publisher = [1,2,3].publisher 88 | 89 | publisher 90 | .append([4,5]) 91 | .append(Set([6,7])) 92 | .append(stride(from: 8, to: 11, by: 2)) 93 | .sink(receiveValue: {print($0)}) 94 | .store(in: &subscriptions) 95 | } 96 | 97 | //append(Publisher) 98 | example(of: "append(Publisher)") { 99 | let publisher1 = [1,2].publisher 100 | let publisher2 = [3,4].publisher 101 | 102 | publisher1 103 | .append(publisher2) 104 | .sink(receiveValue: {print($0)}) 105 | .store(in: &subscriptions) 106 | } 107 | 108 | //Advanced combining 109 | //switchToLatest 110 | example(of: "switchToLatest") { 111 | let publisher1 = PassthroughSubject() 112 | let publisher2 = PassthroughSubject() 113 | let publisher3 = PassthroughSubject() 114 | 115 | let publishers = PassthroughSubject,Error>() 116 | 117 | publishers 118 | .switchToLatest() 119 | .sink(receiveCompletion: {_ in print("Completed!")}, receiveValue: {print($0)}) 120 | .store(in: &subscriptions) 121 | 122 | publishers.send(publisher1) 123 | publisher1.send(1) 124 | publisher1.send(2) 125 | 126 | publishers.send(publisher2) 127 | publisher1.send(3) 128 | publisher2.send(4) 129 | publisher2.send(5) 130 | 131 | publishers.send(publisher3) 132 | publisher2.send(6) 133 | publisher3.send(7) 134 | publisher3.send(8) 135 | publisher3.send(9) 136 | 137 | publisher3.send(completion: .finished) 138 | publishers.send(completion: .finished) 139 | } 140 | 141 | //example(of: "switchToLatest - Network Request") { 142 | // let url = URL(string: "https://source.unsplash.com/random")! 143 | // 144 | // func getImage() -> AnyPublisher{ 145 | // URLSession.shared 146 | // .dataTaskPublisher(for: url) 147 | // .map{data,_ in UIImage(data: data)} 148 | // .print("image") 149 | // .replaceError(with: nil) 150 | // .eraseToAnyPublisher() 151 | // } 152 | // 153 | // let taps = PassthroughSubject() 154 | // 155 | // taps 156 | // .map{_ in getImage()} 157 | // .switchToLatest() 158 | // .sink(receiveValue: {_ in}) 159 | // .store(in: &subscriptions) 160 | // 161 | // taps.send() 162 | // 163 | // DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: { 164 | // taps.send() 165 | // }) 166 | // 167 | // DispatchQueue.main.asyncAfter(deadline: .now() + 3.1, execute: { 168 | // taps.send() 169 | // }) 170 | //} 171 | 172 | //merge(with:) 173 | example(of: "merge(with:)") { 174 | let publisher1 = PassthroughSubject() 175 | let publisher2 = PassthroughSubject() 176 | 177 | publisher1 178 | .merge(with: publisher2) 179 | .sink(receiveValue: {print($0)}) 180 | .store(in: &subscriptions) 181 | 182 | publisher1.send(1) 183 | publisher1.send(2) 184 | publisher1.send(3) 185 | publisher2.send(4) 186 | publisher1.send(5) 187 | 188 | publisher1.send(completion: .finished) 189 | publisher2.send(completion: .finished) 190 | } 191 | 192 | //combineLatest 193 | example(of: "combineLatest") { 194 | let publisher1 = PassthroughSubject() 195 | let publisher2 = PassthroughSubject() 196 | 197 | publisher1 198 | .combineLatest(publisher2) 199 | .sink(receiveCompletion: {_ in print("Completed!")}, receiveValue: {print("p1: \($0), p2: \($1)")}) 200 | .store(in: &subscriptions) 201 | 202 | publisher1.send(1) 203 | publisher1.send(2) 204 | 205 | publisher2.send("a") 206 | publisher2.send("b") 207 | 208 | publisher1.send(3) 209 | 210 | publisher2.send("c") 211 | 212 | publisher1.send(completion: .finished) 213 | publisher2.send(completion: .finished) 214 | } 215 | 216 | 217 | //zip 218 | example(of: "zip") { 219 | let publisher1 = PassthroughSubject() 220 | let publisher2 = PassthroughSubject() 221 | 222 | publisher1 223 | .zip(publisher2) 224 | .sink(receiveCompletion: {_ in print("Completed!")}, receiveValue: {print("p1: \($0), p2: \($1)")}) 225 | .store(in: &subscriptions) 226 | 227 | publisher1.send(1) 228 | publisher1.send(2) 229 | publisher2.send("a") 230 | publisher2.send("b") 231 | publisher1.send(3) 232 | publisher2.send("c") 233 | 234 | publisher1.send(completion: .finished) 235 | publisher2.send(completion: .finished) 236 | } 237 | -------------------------------------------------------------------------------- /Publisher&Subscriber/MyPlayground.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Combine 3 | 4 | //Hello Publisher 5 | example(of: "Publisher") { 6 | let center = NotificationCenter.default 7 | let myNotification = Notification.Name("MyNotification") 8 | let publisher = center.publisher(for: myNotification,object:nil) 9 | let observer = center.addObserver(forName: myNotification, object: nil, queue: nil) { notification in 10 | print("Notification recieved!") 11 | } 12 | center.post(name: myNotification, object: nil) 13 | center.removeObserver(observer) 14 | } 15 | 16 | //Hello Subscriber 17 | example(of: "Subscriber") { 18 | let myNotification = Notification.Name("MyNotification") 19 | let center = NotificationCenter.default 20 | let publisher = center.publisher(for: myNotification,object:nil) 21 | let subscription = publisher 22 | .sink{ _ in 23 | print("Notification recived from publisher") 24 | } 25 | center.post(name: myNotification, object: nil) 26 | subscription.cancel() 27 | } 28 | 29 | //Subscribing with sink(_:_:) 30 | example(of: "Just") { 31 | let just = Just("Hello World") 32 | 33 | _ = just 34 | .sink(receiveCompletion: { 35 | print("Recived Completion",$0) 36 | }, receiveValue: { 37 | print("Recived Value",$0) 38 | }) 39 | 40 | _ = just 41 | .sink(receiveCompletion: { 42 | print("Recived completion (another)",$0) 43 | }, receiveValue: { 44 | print("Recived value (another)",$0) 45 | }) 46 | } 47 | 48 | //Subscribing with assign(to:on:) 49 | example(of: "assign(to:on:)") { 50 | class SomeObject{ 51 | var value:String = "" { 52 | didSet{ 53 | print(value) 54 | } 55 | } 56 | } 57 | 58 | let object = SomeObject() 59 | 60 | let publisher = ["Hello","World"].publisher 61 | _ = publisher 62 | .assign(to: \.value, on: object) 63 | } 64 | 65 | //Republishing with assign(to:) 66 | example(of: "assign(to:)") { 67 | class SomeObjcet{ 68 | @Published var value = 0 69 | } 70 | 71 | let object = SomeObjcet() 72 | 73 | object.$value 74 | .sink{ 75 | print($0) 76 | } 77 | 78 | (0..<10).publisher 79 | .assign(to: &object.$value) 80 | } 81 | 82 | //Publisher protocol 83 | //public protocol Publisher { 84 | // associatedtype Output 85 | // associatedtype Failure : Error 86 | // func receive(subscriber: S) 87 | // where S: Subscriber, 88 | // Self.Failure == S.Failure, 89 | // Self.Output == S.Input 90 | //} 91 | 92 | //extension Publisher { 93 | // public func subscribe(_ subscriber: S) 94 | // where S : Subscriber, 95 | // Self.Failure == S.Failure, 96 | // Self.Output == S.Input 97 | //} 98 | 99 | //Subscriber protocol: 100 | //public protocol Subscriber:CustomCombineIdentifierConvertible{ 101 | // associatedtype Input 102 | // associatedtype Failure:Error 103 | // func recive(subcription:Subscription) 104 | // func recive(_ input:Self.Input) -> Subscribers.Demand 105 | // func recive(completion:Subscribers.Completion) 106 | //} 107 | 108 | // Custom Subscriber 109 | example(of: "Custom Subscriber") { 110 | let publisher = (1...6).publisher 111 | 112 | final class IntSubscriber: Subscriber { 113 | typealias Input = Int 114 | typealias Failure = Never 115 | 116 | func receive(subscription: Subscription) { 117 | subscription.request(.max(3)) 118 | } 119 | 120 | func receive(_ input: Int) -> Subscribers.Demand { 121 | print("Received value", input) 122 | return .none 123 | } 124 | 125 | func receive(completion: Subscribers.Completion) { 126 | print("Received completion", completion) 127 | } 128 | } 129 | 130 | let subscriber = IntSubscriber() 131 | 132 | publisher.subscribe(subscriber) 133 | } 134 | 135 | 136 | // Hello Future 137 | //example(of: "Future") { 138 | // func futureIncrement( 139 | // integer: Int, 140 | // afterDelay delay: TimeInterval) -> Future { 141 | // Future { promise in 142 | // print("Original") 143 | // DispatchQueue.global().asyncAfter(deadline: .now() + delay) { 144 | // promise(.success(integer + 1)) 145 | // } 146 | // } 147 | // } 148 | // 149 | // // 1 150 | // let future = futureIncrement(integer: 1, afterDelay: 3) 151 | // 152 | // // 2 153 | // future 154 | // .sink(receiveCompletion: { print($0) }, 155 | // receiveValue: { print($0) }) 156 | // .store(in: &subscriptions) 157 | // 158 | // future 159 | // .sink(receiveCompletion: { print("Second", $0) }, 160 | // receiveValue: { print("Second", $0) }) 161 | // .store(in: &subscriptions) 162 | //} 163 | 164 | 165 | // Hello Subject 166 | example(of: "PassthroughSubject") { 167 | enum MyError:Error{ 168 | case test 169 | } 170 | 171 | final class StringSubscriber:Subscriber{ 172 | typealias Input = String 173 | 174 | typealias Failure = MyError 175 | 176 | func receive(subscription: Subscription) { 177 | subscription.request(.max(2)) 178 | } 179 | 180 | func receive(_ input: String) -> Subscribers.Demand { 181 | print("Recived Value",input) 182 | return input == "World" ? .max(3) : .none 183 | } 184 | 185 | func receive(completion: Subscribers.Completion) { 186 | print("Received completion",completion) 187 | } 188 | } 189 | 190 | let subscriber = StringSubscriber() 191 | 192 | let subject = PassthroughSubject() 193 | subject.subscribe(subscriber) 194 | let subscription = subject 195 | .sink(receiveCompletion: {completion in 196 | print("Recived completion (sink)",completion) 197 | }, receiveValue: { value in 198 | print("Recived value (sink)",value) 199 | }) 200 | 201 | subject.send("Hello") 202 | subject.send("World") 203 | 204 | subscription.cancel() 205 | subject.send("Still there..?") 206 | subject.send(completion: .failure(MyError.test)) 207 | subject.send(completion: .finished) 208 | subject.send("How about another one..?") 209 | } 210 | 211 | // CurrentValueSubject 212 | example(of: "CurrentValueSubject") { 213 | var subscriptions = Set() 214 | let subject = CurrentValueSubject(0) 215 | 216 | subject 217 | .print() 218 | .sink(receiveValue: { 219 | print($0) 220 | }) 221 | .store(in: &subscriptions) 222 | 223 | subject.send(1) 224 | subject.send(2) 225 | print(subject.value) 226 | subject.value = 3 227 | print(subject.value) 228 | 229 | subject 230 | .print() 231 | .sink(receiveValue: { 232 | print("Second Subscription \($0)") 233 | }) 234 | .store(in: &subscriptions) 235 | 236 | subject.send(completion: .finished) 237 | } 238 | 239 | // Dynamically adjusting demand 240 | example(of: "Dynamically adjusting demand") { 241 | final class IntSubscriber: Subscriber{ 242 | typealias Input = Int 243 | 244 | typealias Failure = Never 245 | 246 | func receive(subscription: Subscription) { 247 | subscription.request(.max(2)) 248 | } 249 | 250 | func receive(_ input: Int) -> Subscribers.Demand { 251 | print("Received Value \(input)") 252 | 253 | switch input{ 254 | case 1: 255 | return .max(2) 256 | case 3: 257 | return .max(1) 258 | default: 259 | return .none 260 | } 261 | } 262 | 263 | func receive(completion: Subscribers.Completion) { 264 | print("Received Completion \(completion)") 265 | } 266 | } 267 | 268 | let subscriber = IntSubscriber() 269 | 270 | let subject = PassthroughSubject() 271 | 272 | subject.subscribe(subscriber) 273 | subject.send(1) 274 | subject.send(2) 275 | subject.send(3) 276 | subject.send(4) 277 | subject.send(5) 278 | subject.send(6) 279 | } 280 | 281 | // Type erasure 282 | example(of: "Type erasure") { 283 | let subject = PassthroughSubject() 284 | 285 | let publisher = subject.eraseToAnyPublisher() 286 | 287 | publisher 288 | .sink(receiveValue: { 289 | print($0) 290 | }) 291 | //.store(in: &subscriptions) 292 | 293 | subject.send(0) 294 | } 295 | 296 | 297 | // Challenge 298 | var subscription = Set() 299 | 300 | example(of: "Create a Blackjack card dealer") { 301 | let dealtHand = PassthroughSubject() 302 | 303 | func deal(_ cardCount: UInt) { 304 | var deck = cards 305 | var cardsRemaining = 52 306 | var hand = Hand() 307 | 308 | for _ in 0 ..< cardCount { 309 | let randomIndex = Int.random(in: 0 ..< cardsRemaining) 310 | hand.append(deck[randomIndex]) 311 | deck.remove(at: randomIndex) 312 | cardsRemaining -= 1 313 | } 314 | 315 | // Add code to update dealtHand here 316 | if hand.points > 21 { 317 | dealtHand.send(completion: .failure(.busted)) 318 | } else { 319 | dealtHand.send(hand) 320 | } 321 | } 322 | 323 | // Add subscription to dealtHand here 324 | _ = dealtHand 325 | .sink(receiveCompletion: { 326 | if case let .failure(error) = $0 { 327 | print(error) 328 | } 329 | }, receiveValue: { hand in 330 | print(hand.cardString, "for", hand.points, "points") 331 | }) 332 | 333 | deal(3) 334 | } 335 | 336 | --------------------------------------------------------------------------------