{"id":308345,"date":"2020-08-12T09:00:08","date_gmt":"2020-08-12T09:00:08","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=308345"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=308345","title":{"rendered":"6 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0438\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 Swift Combine, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0430\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0437\u043d\u0430\u0442\u044c"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/514848\/\"><i><b>\u041f\u0435\u0440\u0435\u0432\u043e\u0434 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d \u0432 \u043f\u0440\u0435\u0434\u0434\u0432\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0440\u0442\u0430 <a href=\"https:\/\/otus.pw\/HdlH\/\">\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u043e\u0433\u043e \u043a\u0443\u0440\u0441\u0430 \u00abiOS-\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u00bb.<\/a><\/b><\/i><\/p>\n<hr>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0448\u0435\u0441\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0432 Combine. \u041c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445, \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u044f \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u0438\u0437 \u043d\u0438\u0445 \u0432 Xcode Playground.<\/p>\n<p>  \u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p>  \u041d\u0443 \u0447\u0442\u043e \u0436, \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0438\u0445 \u0440\u0430\u0437\u0433\u043b\u0430\u0433\u043e\u043b\u044c\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0439, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c.<a name=\"habracut\"><\/a><\/p>\n<h3>1. prepend<\/h3>\n<p>  \u042d\u0442\u0430 \u0433\u0440\u0443\u043f\u043f\u0430 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c (prepend \u2014 \u0434\u043e\u0441\u043b\u043e\u0432\u043d\u043e \u201c\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e\u201d) \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c\u0443 \u043f\u0430\u0431\u043b\u0438\u0448\u0435\u0440\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u0430\u0431\u043b\u0438\u0448\u0435\u0440\u043e\u0432:<\/p>\n<pre><code class=\"swift\">import Foundation import Combine  var subscriptions = Set&lt;AnyCancellable&gt;()  func prependOutputExample() {     let stringPublisher = [&quot;World!&quot;].publisher          stringPublisher         .prepend(&quot;Hello&quot;)         .sink(receiveValue: { print($0) })         .store(in: &amp;subscriptions) }<\/code><\/pre>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: <code>Hello<\/code> \u0438 <code>World<\/code>! \u0432\u044b\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/k8\/if\/rd\/k8ifrdahf3vovb55ztd1jwtd5hs.png\"><\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f \u0442\u043e\u0433\u043e \u0436\u0435 \u0442\u0438\u043f\u0430:<\/p>\n<pre><code class=\"swift\">func prependPublisherExample() {     let subject = PassthroughSubject&lt;String, Never&gt;()     let stringPublisher = [&quot;Break things!&quot;].publisher          stringPublisher         .prepend(subject)         .sink(receiveValue: { print($0) })         .store(in: &amp;subscriptions)          subject.send(&quot;Run code&quot;)     subject.send(completion: .finished) }<\/code><\/pre>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c\u0443 (\u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <code>.finished<\/code> \u0432 subject, \u0447\u0442\u043e\u0431\u044b \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>.prepend<\/code> \u0440\u0430\u0431\u043e\u0442\u0430\u043b):<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/8q\/ol\/ra\/8qolrao3lr3iuu7fjdfwgnkxnte.png\"><\/p>\n<h3>2. append<\/h3>\n<p>  \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>.append<\/code> (\u0434\u043e\u0441\u043b\u043e\u0432\u043d\u043e \u201c\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043a\u043e\u043d\u0435\u0446\u201d) \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e <code>.prepend<\/code>, \u043d\u043e \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c\u0443 \u043f\u0430\u0431\u043b\u0438\u0448\u0435\u0440\u0443:<\/p>\n<pre><code class=\"swift\">func appendOutputExample() {     let stringPublisher = [&quot;Hello&quot;].publisher          stringPublisher         .append(&quot;World!&quot;)         .sink(receiveValue: { print($0) })         .store(in: &amp;subscriptions) }<\/code><\/pre>\n<p>  \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u0432\u0438\u0434\u0438\u043c <code>Hello<\/code> \u0438 <code>World<\/code>! \u0432\u044b\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u043d\u0430 \u043a\u043e\u043d\u0441\u043e\u043b\u0438:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/0_\/pq\/j2\/0_pqj27vxyxaainsp62kxmmvc_o.png\"><\/p>\n<p>  \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0442\u043e\u043c\u0443, \u043a\u0430\u043a \u0440\u0430\u043d\u0435\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 <code>.prepend<\/code> \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433\u043e\u0433\u043e <code>Publisher<\/code>\u0430, \u0443 \u043d\u0430\u0441 \u0442\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438 \u0434\u043b\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <code>.append<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/xy\/yf\/qa\/xyyfqaftjplv2ebv0mrp-hia0wq.png\"><\/p>\n<h3>3. switchToLatest<\/h3>\n<p>  \u0411\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>.switchToLatest<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0441\u0435\u0440\u0438\u044e \u043f\u0430\u0431\u043b\u0438\u0448\u0435\u0440\u043e\u0432 \u0432 \u043e\u0434\u0438\u043d \u043f\u043e\u0442\u043e\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439:<\/p>\n<pre><code class=\"swift\">func switchToLatestExample() {     let stringSubject1 = PassthroughSubject&lt;String, Never&gt;()     let stringSubject2 = PassthroughSubject&lt;String, Never&gt;()     let stringSubject3 = PassthroughSubject&lt;String, Never&gt;()          let subjects = PassthroughSubject&lt;PassthroughSubject&lt;String, Never&gt;, Never&gt;()          subjects         .switchToLatest()         .sink(receiveValue: { print($0) })         .store(in: &amp;subscriptions)          subjects.send(stringSubject1)          stringSubject1.send(&quot;A&quot;)          subjects.send(stringSubject2)          stringSubject1.send(&quot;B&quot;) \/\/ \u043e\u0442\u0431\u0440\u043e\u0448\u0435\u043d\u043e          stringSubject2.send(&quot;C&quot;)     stringSubject2.send(&quot;D&quot;)          subjects.send(stringSubject3)          stringSubject2.send(&quot;E&quot;) \/\/ \u043e\u0442\u0431\u0440\u043e\u0448\u0435\u043d\u043e     stringSubject2.send(&quot;F&quot;) \/\/ \u043e\u0442\u0431\u0440\u043e\u0448\u0435\u043d\u043e          stringSubject3.send(&quot;G&quot;)          stringSubject3.send(completion: .finished) } <\/code><\/pre>\n<p>  \u0412\u043e\u0442 \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043a\u043e\u0434\u0435:<\/p>\n<ul>\n<li>\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0440\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <code>PassthroughSubject<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.<\/li>\n<li>\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 <code>PassthroughSubject<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b <code>PassthroughSubject<\/code>.<\/li>\n<li>\u041c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c <code>stringSubject1<\/code> \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 subject.<\/li>\n<li><code>stringSubject1<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 A. <\/li>\n<li>\u041c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c <code>stringSubject2<\/code> \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 subject, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f stringSubject1.<\/li>\n<li>\u0422\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 <code>stringSubject2<\/code>, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u0441\u044f \u043a <code>stringSubject3<\/code> \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u043c\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f.<\/li>\n<\/ul>\n<p>  \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u0432\u0438\u0434\u0438\u043c \u0432\u044b\u0432\u043e\u0434 <code>A<\/code>, <code>C<\/code>, <code>D<\/code> \u0438 <code>G<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/5d\/cg\/p0\/5dcgp0caa_hiuvqf7oybydytn74.png\"><\/p>\n<p>  \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b, \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>isAvailable<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>Bool<\/code> \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438.<\/p>\n<pre><code class=\"swift\">func switchToLatestExample2() {     func isAvailable(query: String) -&gt; Future&lt;Bool, Never&gt; {         return Future { promise in             DispatchQueue.main.asyncAfter(deadline: .now() + 2) {                 promise(.success(Bool.random()))             }         }     }          let searchSubject = PassthroughSubject&lt;String, Never&gt;()          searchSubject         .print(&quot;subject&quot;)         .map { isAvailable(query: $0) }         .print(&quot;search&quot;)         .switchToLatest()         .sink(receiveValue: { print($0) })         .store(in: &amp;subscriptions)          searchSubject.send(&quot;Query 1&quot;)     DispatchQueue.main.asyncAfter(deadline: .now() + 1) {         searchSubject.send( &quot;Query 2&quot;)     } }<\/code><\/pre>\n<p>  \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0443 <code>.switchToLatest<\/code> \u043c\u044b \u0434\u043e\u0441\u0442\u0438\u0433\u0430\u0435\u043c \u0442\u043e\u0433\u043e, \u0447\u0435\u0433\u043e \u0445\u043e\u0442\u0438\u043c. \u0422\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 Bool \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0432\u0435\u0434\u0435\u043d\u043e \u043d\u0430 \u044d\u043a\u0440\u0430\u043d:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/bt\/r0\/vk\/btr0vkmrcsf8w9niuxtqv1lrmvo.png\"><\/p>\n<h3>4. merge(with:)<\/h3>\n<p>  \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>.merge(with:)<\/code> \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0434\u0432\u0443\u0445 <code>Publishers<\/code>\u043e\u0432, \u043a\u0430\u043a \u0435\u0441\u043b\u0438 \u0431\u044b \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442 \u043e\u0434\u043d\u043e\u0433\u043e:<\/p>\n<pre><code class=\"swift\">func mergeWithExample() {     let stringSubject1 = PassthroughSubject&lt;String, Never&gt;()     let stringSubject2 = PassthroughSubject&lt;String, Never&gt;()          stringSubject1         .merge(with: stringSubject2)         .sink(receiveValue: { print($0) })         .store(in: &amp;subscriptions)          stringSubject1.send(&quot;A&quot;)          stringSubject2.send(&quot;B&quot;)          stringSubject2.send(&quot;C&quot;)          stringSubject1.send(&quot;D&quot;) } <\/code><\/pre>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0434\u0443\u044e\u0449\u0430\u044f\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/bt\/r0\/vk\/btr0vkmrcsf8w9niuxtqv1lrmvo.png\"><\/p>\n<h3>5. combineLatest<\/h3>\n<p>  \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>.combineLatest<\/code> \u043f\u0430\u0431\u043b\u0438\u0448\u0438\u0442 \u043a\u043e\u0440\u0442\u0435\u0436, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440: \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0438\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043f\u0430\u0440\u043e\u043b\u044c <code>UITextFields<\/code> \u0438 \u043a\u043d\u043e\u043f\u043a\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f. \u041c\u044b \u0445\u043e\u0442\u0438\u043c \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0439 \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u0438\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435 \u043f\u044f\u0442\u0438 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u0430 \u043f\u0430\u0440\u043e\u043b\u044c \u2014 \u043d\u0435 \u043c\u0435\u043d\u0435\u0435 \u0432\u043e\u0441\u044c\u043c\u0438. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043b\u0435\u0433\u043a\u043e \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u044d\u0442\u043e\u0433\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>.combineLatest<\/code>:<\/p>\n<pre><code class=\"swift\">func combineLatestExample() {     let usernameTextField = CurrentValueSubject&lt;String, Never&gt;(&quot;&quot;)     let passwordTextField = CurrentValueSubject&lt;String, Never&gt;(&quot;&quot;)          let isButtonEnabled = CurrentValueSubject&lt;Bool, Never&gt;(false)          usernameTextField         .combineLatest(passwordTextField)         .handleEvents(receiveOutput: { (username, password) in             print(&quot;Username: \\(username), password: \\(password)&quot;)             let isSatisfied = username.count &gt;= 5 &amp;&amp; password.count &gt;= 8             isButtonEnabled.send(isSatisfied)         })         .sink(receiveValue: { _ in })         .store(in: &amp;subscriptions)          isButtonEnabled         .sink { print(&quot;isButtonEnabled: \\($0)&quot;) }         .store(in: &amp;subscriptions)          usernameTextField.send(&quot;user&quot;)     usernameTextField.send(&quot;user12&quot;)          passwordTextField.send(&quot;12&quot;)     passwordTextField.send(&quot;12345678&quot;) }<\/code><\/pre>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a <code>usernameTextField <\/code>\u0438 <code>passwordTextField<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0442 <code>user12<\/code> \u0438 <code>12345678<\/code> \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u0435\u0442\u0441\u044f, \u0438 \u043a\u043d\u043e\u043f\u043a\u0430 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442\u0441\u044f:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/et\/21\/z4\/et21z4wmpguxu0vsslpy-byk2l8.png\"><\/p>\n<h3>6. zip<\/h3>\n<p>  \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>.zip<\/code> \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0430\u0440\u0443 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043e\u0442 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f. \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u043f\u0430\u0431\u043b\u0438\u0448\u0438\u043b\u0438 \u043b\u0438 \u043e\u0431\u0430 \u043f\u0430\u0431\u043b\u0438\u0448\u0435\u0440\u0430 \u043e\u0434\u043d\u043e \u0438 \u0442\u043e \u0436\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>Int<\/code>:<\/p>\n<pre><code class=\"swift\">func zipExample() {     let intSubject1 = PassthroughSubject&lt;Int, Never&gt;()     let intSubject2 = PassthroughSubject&lt;Int, Never&gt;()          let foundIdenticalPairSubject = PassthroughSubject&lt;Bool, Never&gt;()          intSubject1         .zip(intSubject2)         .handleEvents(receiveOutput: { (value1, value2) in             print(&quot;value1: \\(value1), value2: \\(value2)&quot;)             let isIdentical = value1 == value2             foundIdenticalPairSubject.send(isIdentical)         })         .sink(receiveValue: { _ in })         .store(in: &amp;subscriptions)          foundIdenticalPairSubject         .sink(receiveValue: { print(&quot;is identical: \\($0)&quot;) })         .store(in: &amp;subscriptions)          intSubject1.send(0)     intSubject1.send(1)          intSubject2.send(4)          intSubject1.send(6)     intSubject2.send(1)     intSubject2.send(7)          intSubject2.send(9) \/\/ \u041d\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0435\u0433\u043e \u043f\u0430\u0440\u0430 \u0435\u0449\u0435 \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 }<\/code><\/pre>\n<p>  \u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 <code>intSubject1<\/code> \u0438 <code>intSubject2<\/code>:<\/p>\n<ul>\n<li>0 \u0438 4<\/li>\n<li>1 \u0438 1<\/li>\n<li>6 \u0438 7<\/li>\n<\/ul>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>9<\/code> \u043d\u0435 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u0441\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 <code>intSubject1<\/code> \u0435\u0449\u0435 \u043d\u0435 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/gv\/qo\/oe\/gvqooeqpobxv-htrwo3vabwdjvy.png\"><\/p>\n<h3>\u0420\u0435\u0441\u0443\u0440\u0441\u044b<\/h3>\n<p>  \u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <a href=\"https:\/\/gist.github.com\/zafarivaev\/64f48ec746996a0e76fe3b4a69a7e696\">Gist<\/a>.<\/p>\n<h3>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>  \u0412\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u0442\u0438\u043f\u044b \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 Combine? \u041d\u0435 \u0441\u0442\u0435\u0441\u043d\u044f\u0439\u0442\u0435\u0441\u044c \u043f\u043e\u0441\u0435\u0449\u0430\u0442\u044c \u043c\u043e\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438:<\/p>\n<ul>\n<li><a href=\"https:\/\/medium.com\/better-programming\/5-transforming-combine-operators-you-should-know-4603fe112d74\">5 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 Combine, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0430\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0437\u043d\u0430\u0442\u044c<\/a><\/li>\n<li><a href=\"https:\/\/medium.com\/better-programming\/5-transforming-combine-operators-you-should-know-4603fe112d74\">9 \u0444\u0438\u043b\u044c\u0442\u0440\u0443\u044e\u0449\u0438\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 Combine, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0430\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0437\u043d\u0430\u0442\u044c<\/a>  <\/li>\n<\/ul>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/514848\/\"> https:\/\/habr.com\/ru\/company\/otus\/blog\/514848\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/514848\/\"><i><b>\u041f\u0435\u0440\u0435\u0432\u043e\u0434 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d \u0432 \u043f\u0440\u0435\u0434\u0434\u0432\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0440\u0442\u0430 <a href=\"https:\/\/otus.pw\/HdlH\/\">\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u043e\u0433\u043e \u043a\u0443\u0440\u0441\u0430 \u00abiOS-\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u00bb.<\/a><\/b><\/i><\/p>\n<hr>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0448\u0435\u0441\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0432 Combine. \u041c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445, \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u044f \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u0438\u0437 \u043d\u0438\u0445 \u0432 Xcode Playground.<\/p>\n<p>  \u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p>  \u041d\u0443 \u0447\u0442\u043e \u0436, \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0438\u0445 \u0440\u0430\u0437\u0433\u043b\u0430\u0433\u043e\u043b\u044c\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0439, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-308345","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308345","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=308345"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308345\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=308345"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=308345"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=308345"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}