├── 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 | 
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 |
--------------------------------------------------------------------------------