Giter Site home page Giter Site logo

combinecocoa's Introduction

CombineCocoa



Build Status
CombineCocoa supports CocoaPods CombineCocoa supports Swift Package Manager (SPM) CombineCocoa supports Carthage

CombineCocoa attempts to provide publishers for common UIKit controls so you can consume user interaction as Combine emissions and compose them into meaningful, logical publisher chains.

Note: This is still a primal version of this, with much more to be desired. I gladly accept PRs, ideas, opinions, or improvements. Thank you ! :)

Basic Examples

Check out the Example in the Example folder. Open the project in Xcode 11 and Swift Package Manager should automatically resolve the required dependencies.

Usage

tl;dr:

import Combine
import CombineCocoa

textField.textPublisher // AnyPublisher<String, Never>
segmented.selectedSegmentIndexPublisher // AnyPublisher<Int, Never>
slider.valuePublisher // AnyPublisher<Float, Never>
button.tapPublisher // AnyPublisher<Void, Never>
barButtonItem.tapPublisher // AnyPublisher<Void, Never>
switch.isOnPublisher // AnyPublisher<Bool, Never>
stepper.valuePublisher // AnyPublisher<Double, Never>
datePicker.datePublisher // AnyPublisher<Date, Never>
refreshControl.isRefreshingPublisher // AnyPublisher<Bool, Never>
pageControl.currentPagePublisher // AnyPublisher<Int, Never>
tapGesture.tapPublisher // AnyPublisher<UITapGestureRecognizer, Never>
pinchGesture.pinchPublisher // AnyPublisher<UIPinchGestureRecognizer, Never>
rotationGesture.rotationPublisher // AnyPublisher<UIRotationGestureRecognizer, Never>
swipeGesture.swipePublisher // AnyPublisher<UISwipeGestureRecognizer, Never>
panGesture.panPublisher // AnyPublisher<UIPanGestureRecognizer, Never>
screenEdgePanGesture.screenEdgePanPublisher // AnyPublisher<UIScreenEdgePanGestureRecognizer, Never>
longPressGesture.longPressPublisher // AnyPublisher<UILongPressGestureRecognizer, Never>
scrollView.contentOffsetPublisher // AnyPublisher<CGPoint, Never>
scrollView.reachedBottomPublisher(offset:) // AnyPublisher<Void, Never>

Installation

CocoaPods

Add the following line to your Podfile:

pod 'CombineCocoa'

Swift Package Manager

Add the following dependency to your Package.swift file:

.package(url: "https://github.com/CombineCommunity/CombineCocoa.git", from: "0.2.1")

Carthage

Add the following to your Cartfile:

github "CombineCommunity/CombineCocoa"

Future ideas

  • Support non UIControl.Event-based publishers (e.g. delegates).
  • ... your ideas? :)

Acknowledgments

License

MIT, of course ;-) See the LICENSE file.

The Apple logo and the Combine framework are property of Apple Inc.

combinecocoa's People

Contributors

bpollman avatar dochoi-bot avatar freak4pc avatar henrimagi avatar hsncr avatar iamrado avatar icanzilb avatar itsol-ka avatar jdisho avatar kevinrenskers avatar kisekied avatar patrickbdev avatar ronkliffer avatar roshannindrai avatar stepan-votava avatar ttozzi avatar wickwirew avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

combinecocoa's Issues

UICollectionView Crash when using delegate publishers and UICollectionViewDiffableDataSource

Describe the bug
The UICollectionView crashes internally when using the delegate publishers such as didSelectItemPublisher and using UICollectionViewDiffableDataSource as dataSource.

To Reproduce

  1. Setup a collectionView with UICollectionViewDiffableDataSource as dataSource.
  2. Add an example publisher such as didSelectItemPublisher
  3. Update dataSource snapshot
  4. See crash log

Expected behavior
Shouldn't crash

Device:

  • OS: [e.g. iOS 14.5]
  • CombineCocoa 0.3.0

Additional context

Crash Log:

2021-08-04 11:21:52.800547+0100 App[6134:8095978] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(
	0   CoreFoundation                      0x0000000113473fba __exceptionPreprocess + 242
	1   libobjc.A.dylib                     0x0000000112bc1ff5 objc_exception_throw + 48
	2   CoreFoundation                      0x00000001134f2523 _CFThrowFormattedException + 194
	3   CoreFoundation                      0x00000001134f0457 -[__NSArrayM insertObject:atIndex:].cold.2 + 0
	4   CoreFoundation                      0x000000011337114a -[__NSArrayM insertObject:atIndex:] + 1130
	5   Runtime                             0x000000010f64a5b8 unpackInvocation + 1410
	6   Runtime                             0x000000010f649fdd -[ObjcDelegateProxy forwardInvocation:] + 45
	7   CoreFoundation                      0x0000000113478259 ___forwarding___ + 825
	8   CoreFoundation                      0x000000011347a7a8 _CF_forwarding_prep_0 + 120
	9   UIKitCore                           0x000000012ddf07cd -[UICollectionView _notifyDidEndDisplayingCellIfNeeded:forIndexPath:] + 194
	10  UIKitCore                           0x000000012de07b5a -[UICollectionView _reuseCell:notifyDidEndDisplaying:] + 1471
	11  UIKit                               0x0000000150773878 -[UICollectionViewAccessibility _reuseCell:notifyDidEndDisplaying:] + 77
	12  UIKitCore                           0x000000012de17202 -[UICollectionView _updateAnimationDidStop:finished:context:] + 1838
	13  UIKitCore                           0x000000012de169e4 __102-[UICollectionView _updateWithItems:tentativelyForReordering:propertyAnimator:collectionViewAnimator:]_block_invoke.2110 + 77
	14  libdispatch.dylib                   0x0000000119698578 _dispatch_call_block_and_release + 12
	15  libdispatch.dylib                   0x000000011969974e _dispatch_client_callout + 8
	16  libdispatch.dylib                   0x00000001196a7b3f _dispatch_main_queue_callback_4CF + 1152
	17  CoreFoundation                      0x00000001133e18f8 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
	18  CoreFoundation                      0x00000001133dc169 __CFRunLoopRun + 2781
	19  CoreFoundation                      0x00000001133db1a7 CFRunLoopRunSpecific + 567
	20  GraphicsServices                    0x0000000122ed0d85 GSEventRunModal + 139
	21  UIKitCore                           0x000000012e7184df -[UIApplication _run] + 912
	22  UIKitCore                           0x000000012e71d39c UIApplicationMain + 101
	23  libswiftUIKit.dylib                 0x0000000118266f42 $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 98
	24  App                                0x000000010ef3c40a $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 122
	25  App                                0x000000010ef3c37c $s4App11AppDelegateC5$mainyyFZ + 28
	26  App                                0x000000010ef3c4f9 main + 41
	27  libdyld.dylib                       0x0000000119727bbd start + 1
)
libc++abi: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
terminating with uncaught exception of type NSException

Privacy Manifest

From Apple docs:

Starting in spring 2024, you must include the privacy manifest for any SDK listed below when you submit new apps in App Store Connect that include those SDKs, or when you submit an app update that adds one of the listed SDKs as part of the update. Signatures are also required in these cases where the listed SDKs are used as binary dependencies.

Could you please add a privacy manifest for this library?

UIGestureRecognizer publisher

Have you considered adding a publisher for gesture recognisers? Would be neat.

Iโ€™m happy to have a look at adding myself, just wanted to raise the issue to track.

Big issue with the delegate proxies

It seems that a delegate proxy can only be used on one item of its kind at a time.

For example in this screen, there are two view controllers, both have a UISearchBar. The one in the main view controller works completely fine, but the one on the half-modal (that has focus) doesn't do anything, none of the new publishers (for example searchBar.textDidChangePublisher) fire. Until I remove the delegate publishers from the other search bar, and then it works in the modal.

Screen Shot 2020-10-06 at 14 21 03

Memory Leaks in TapPublisher

Describe the bug
We seems to be getting memory leaks with TapPublisher.

To Reproduce
Steps to reproduce the behavior:
Add a tapPublisher on a tapRecognizer
Expected behavior
No Memory Leaks

Screenshots

Screen Shot 2022-03-03 at 9 27 13 PM

Screen Shot 2022-03-03 at 9 32 38 PM

Screen Shot 2022-03-03 at 9 32 47 PM

Device:

  • Device: [e.g. iPhone X]
  • CombineCocoa version 0.4.0

Additional context
None

can't assign Publisher to Button Tapped Publisher

Describe the bug
Key path value type 'ReferenceWritableKeyPath<UIButton, Void>' cannot be converted to contextual type 'KeyPath< UIButton, Void>'To Reproduce
var tappedSubject = CurrentValueSubject<Void,Never>({}())
var signUPTapped: AnyPublisher<Void, Never> {
tappedSubject.map {_ in
self.showAlert()
}
.eraseToAnyPublisher()
}

    viewModel.tappedSubject
        .assign(to: \.tapPublisher, on: signUpButton)

i get error when do this

How to use in `UIImagePickerController`

Trying to add a publisher to UIImagePickerController using a DelegateProxy

My code:

extension UIImagePickerController {
  var didFinishPickingMedia: AnyPublisher<[UIImagePickerController.InfoKey: Any], Never> {
    let didPickSelector =
      #selector(UIImagePickerControllerDelegate.imagePickerController(_:didFinishPickingMediaWithInfo:))

    return delegateProxy
      .interceptSelectorPublisher(didPickSelector)
      .map { $0[1] as! [UIImagePickerController.InfoKey: Any] }
      .eraseToAnyPublisher()
  }

  var didCancel: AnyPublisher<Void, Never> {
    let didCancelSelector = #selector(UIImagePickerControllerDelegate.imagePickerControllerDidCancel(_:))
    return delegateProxy
      .interceptSelectorPublisher(didCancelSelector)
      .map { _ in () }
      .eraseToAnyPublisher()
  }

  private var delegateProxy: UIImagePickerControllerDelegateProxy {
      .createDelegateProxy(for: self)
  }
}

private class UIImagePickerControllerDelegateProxy: DelegateProxy,
                                                    UIImagePickerControllerDelegate,
                                                    UINavigationControllerDelegate,
                                                    DelegateProxyType {
  func setDelegate(to object: UIImagePickerController) {
    object.delegate = self
  }
}

Works well on devices but crashes when presenting the controller on a simulator with 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'.

ControlProperty & ControlEvent don't call removeTarget in cancel method

Both classes invoke control.addTarget(self, action: #selector(handleEvent), for: event) but forget to call control.removeTarget in cancel method leaving a reference to self. Since the target is not retained, it is possible that it is not causing an issue though (it may be weak inside the control) but it would be preferable to be consistent and follow Apple recommendation "To stop the delivery of events, always call the removeTarget(_:action:for:) method."

button can not touch up

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Device:

  • Device: [e.g. iPhone 11]
  • OS: [e.g. iOS 13.4]
  • CombineCocoa version

Additional context
Add any other context about the problem here.

how to send a new output for UITextfiled

if i set a subsriber for UITextfield's textPublisher,

and i changed the UITextfield's content by code like this:

textField.text = "some value"

that subscriber can't receive the output.

so, can i send a signal by myself?

something like this:

textField.textPublisher.send("some Value")

Contribution

What do you think about working on it together? I've got few ideas. What can I do?

No framework output when using Carthage

Describe the bug

To Reproduce
Steps to reproduce the behavior:

  1. Add "CombineCommunity/CombineCocoa" to Cartfile
  2. Run Carthage update --platform iOS

Expected behavior
CombineCocoa builds and produces CombineCocoa.framework

What is happening

Following message appears during Carthage process

*** Skipped building CombineCocoa due to the error:
Dependency "CombineCocoa" has no shared framework schemes for any of the platforms: iOS

Device:

  • CombineCocoa version - latest

Only last UITextView subscriber receives events

First of all, thanks for all of your hard work. I appreciate the additions to Combine in both the Cocoa and Ext packages. They have helped bridge the gap between RxSwift and Combine.
Describe the bug

To Reproduce
I have an issue with UITextView. If I have multiple subscriptions to the same textView textPublisher, only the last subscription receives events. I have tested other controls, and they work as expected, so I believe this issue is specific to UITextView. I have a sample project that I could pass along; however, the issue is easy to reproduce.
Steps to reproduce the behavior:

  1. Create a UItextView in the storyboard
  2. Add an outlet to viewcontroller
  3. Create two subscriptions to the textPublisher
  4. run the app and add input to the UItextView
  5. Only the last subscription receives updates

Expected behavior
I expect both subscriptions to receive text input updates

Additional context

  • CombineCocoa version (0.2.2)

Example:

class ViewController: UIViewController {
    private var disposables = Set<AnyCancellable>()
    @IBOutlet var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.textPublisher
            .sink { text in
                print("Subscription-1 \(text)")
            }
            .store(in: &disposables)

        textView.textPublisher
            .sink { text in
                print("Subscription-2 \(text)")
            }
            .store(in: &disposables)
    }
}

produces the following output:

Subscription-1 Optional("")
Subscription-2 Optional("")
Subscription-2 Optional("T")
Subscription-2 Optional("Th")
Subscription-2 Optional("Thi")
Subscription-2 Optional("This")
Subscription-2 Optional("This ")
Subscription-2 Optional("This i")
Subscription-2 Optional("This is")
Subscription-2 Optional("This is ")
Subscription-2 Optional("This is a")
Subscription-2 Optional("This is a ")
Subscription-2 Optional("This is a m")
Subscription-2 Optional("This is a me")
Subscription-2 Optional("This is a mes")
Subscription-2 Optional("This is a mess")
Subscription-2 Optional("This is a messa")
Subscription-2 Optional("This is a messag")
Subscription-2 Optional("This is a message")

UIScrollView publishers issue in version 0.4.0

I have build error for this publishers:

/// Combine wrapper for `scrollViewWillBeginZooming(_:with:)`
var willBeginZoomingPublisher: AnyPublisher<UIView?, Never> {
    let selector = #selector(UIScrollViewDelegate.scrollViewWillBeginZooming(_:with:))
    return delegateProxy.interceptSelectorPublisher(selector)
        .map { $0[1] as! UIView? } // โŒ Cannot downcast from 'Any' to a more optional type 'UIView?'
        .eraseToAnyPublisher()
}

/// Combine wrapper for `scrollViewDidEndZooming(_:with:atScale:)`
var didEndZooming: AnyPublisher<(view: UIView?, scale: CGFloat), Never> {
    let selector = #selector(UIScrollViewDelegate.scrollViewDidEndZooming(_:with:atScale:))
    return delegateProxy.interceptSelectorPublisher(selector)
        .map { ($0[1] as! UIView?, $0[2] as! CGFloat) } // โŒ Cannot downcast from 'Any' to a more optional type 'UIView?'
        .eraseToAnyPublisher()
}

CombineCocoa 0.4.0
Xcode 12.4
Swift 5.3.2

FeatureRequest: Add handlers for selectors

Feature request

In ReactiveCocoa there is an ability to subscribe to object selector's trigger like

navigationController?.reactive
        .trigger(for: #selector(UINavigationController.popViewController))
        .producer.observe(on: UIScheduler()).startWithValues { ... }

I think this feature is very useful and it would be great if Combine had this ability too ๐Ÿ™

Umbrella directory '/Users/freak4pc/Work/OSS/CombineCocoa/Sources/Runtime/include' not found

Project does not build. There is a generated modulemap file inside .xcodeproj that references some static directory on freak4pc's mac.

Umbrella directory '/Users/freak4pc/Work/OSS/CombineCocoa/Sources/Runtime/include' not found warning creates 8 errors that indicates; Runtime framework classes are not found.

After fixing the reference inside modulemap file that mentions "umbrella "/Users/freak4pc/Work/OSS/CombineCocoa/Sources/Runtime/include", project builds successfully.

However I can't run carthage command successfully, it resets the path.

Steps to reproduce the behavior:

  1. Download project and build.
  2. "Umbrella directory '/Users/freak4pc/Work/OSS/CombineCocoa/Sources/Runtime/include' not found" warning creates 8 errors.

Expected behavior
Runtime framework headers can be found.

  • Xcode 12.2
  • Device: Sim
  • OS: iOS 14.0.1
  • CombineCocoa version 0.2.2 on console, however 0.2.1 on project settings.

Could you guys please help?

How can I add a textPublisher to UITextView?

Since UITextView doesn't subclass UIControl I can't just do something like this

public extension UITextView {
    /// A publisher emitting any text changes to a this text field.
    var textPublisher: AnyPublisher<String?, Never> {
        Publishers.ControlProperty(control: self, events: [.allEditingEvents, .valueChanged], keyPath: \.text)
                  .eraseToAnyPublisher()
    }
}

So how would you add such a publisher?

tableView(_:viewForHeaderInSection:) delegate method cannot be used

Describe the bug
tableView(_:viewForHeaderInSection:) delegate method cannot be used when using tableView.didEndScrollingAnimationPublisher.

To Reproduce

class MyViewController: UIViewController {
    @IBOutlet private weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.didEndScrollingAnimationPublisher
            .sink { print("didEndScrollingAnimation") }
    }
}

extension MyViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        // return my header view
    }
}

MyViewController is configured as a delegate of tableView in a storyboard.

Expected behavior
tableView(_:viewForHeaderInSection:) is called

Device:

  • Device: iPhone 14
  • OS: iOS 16
  • 0.4.1

Additional context
RxCocoa supports this by calling tableView.rx.setDelegate(viewController).

textPublisher crash when using emoji

I have two UITextView's that I am using textPublisher on, to keep them in sync with each other.

Simulator Screen Shot - iPhone 12 Pro - 2020-11-06 at 11 48 58

import UIKit
import Combine
import CombineCocoa

class ViewController: UIViewController {
  @IBOutlet var textView1: UITextView!
  @IBOutlet var textView2: UITextView!

  @Published var value: String? = ""

  private var subscriptions = Set<AnyCancellable>()

  override func viewDidLoad() {
    super.viewDidLoad()

    $value
      .sink {
        self.textView1.text = $0
        self.textView2.text = $0
      }
      .store(in: &subscriptions)

    textView1.textPublisher
      .assign(to: \.value, on: self)
      .store(in: &subscriptions)

    textView2.textPublisher
      .assign(to: \.value, on: self)
      .store(in: &subscriptions)
  }
}

It all works, until you type an emoji: then the app crashes.

2020-11-06 11:49:04.184903+0100 CombineCocoaTest[7757:188602] requesting caretRectForPosition: while the NSTextStorage has oustanding changes {0, 8}
2020-11-06 11:49:04.185022+0100 CombineCocoaTest[7757:188602] !!! _NSLayoutTreeLineFragmentRectForGlyphAtIndex invalid glyph index 7
2020-11-06 11:49:04.191460+0100 CombineCocoaTest[7757:188602] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[NSLayoutManager _fillLayoutHoleForCharacterRange:desiredNumberOfLines:isSoft:] *** attempted layout while textStorage is editing.  It is not valid to cause the layoutManager to do layout while the textStorage is editing (ie the textStorage has been sent a beginEditing message without a matching endEditing.)'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff2043a126 __exceptionPreprocess + 242
	1   libobjc.A.dylib                     0x00007fff20177f78 objc_exception_throw + 48
	2   CoreFoundation                      0x00007fff2043a004 -[NSException initWithCoder:] + 0
	3   UIFoundation                        0x00007fff2398ba17 -[NSLayoutManager(NSPrivate) _fillLayoutHoleForCharacterRange:desiredNumberOfLines:isSoft:] + 587
	4   UIFoundation                        0x00007fff23993d19 _NSFastFillAllLayoutHolesForGlyphRange + 1594
	5   UIFoundation                        0x00007fff2399155c -[NSLayoutManager(NSPrivate) _rectArrayForRange:withinSelectionRange:rangeIsCharRange:singleRectOnly:fullLineRectsOnly:inTextContainer:rectCount:rangeWithinContainer:glyphsDrawOutsideLines:rectArray:rectArrayCapacity:] + 750
	6   UIFoundation                        0x00007fff2399456f -[NSLayoutManager(NSPrivate) _rectArrayForRange:withinSelectionRange:rangeIsCharRange:singleRectOnly:fullLineRectsOnly:inTextContainer:rectCount:rangeWithinContainer:glyphsDrawOutsideLines:] + 69
	7   UIFoundation                        0x00007fff239e3541 -[NSLayoutManager rectArrayForCharacterRange:withinSelectedCharacterRange:inTextContainer:rectCount:] + 35
	8   UIKitCore                           0x00007fff24a037e1 -[_UITextContainerView updateInsertionPointStateAndRestartTimer:] + 259
	9   UIFoundation                        0x00007fff2399920e -[NSLayoutManager(NSPrivate) _invalidateLayoutForExtendedCharacterRange:isSoft:invalidateUsage:] + 2247
	10  UIKitCore                           0x00007fff249f0121 -[UITextView setAttributedText:] + 1000
	11  UIKitCore                           0x00007fff249fa518 -[UITextView setText:] + 121
	12  CombineCocoaTest                    0x000000010435e863 $s16CombineCocoaTest20SearchViewControllerC11viewDidLoadyyFySSSgcfU_ + 387
	13  CombineCocoaTest                    0x000000010435ea71 $sSSSgIegg_AAIegn_TR + 33
	14  Combine                             0x00007fff4a6a7566 $s7Combine11SubscribersO4SinkC7receiveyAC6DemandVxF + 54
	15  Combine                             0x00007fff4a6a7c60 $s7Combine11SubscribersO4SinkCy_xq_GAA10SubscriberA2aGP7receiveyAC6DemandV5InputQzFTW + 16
	16  Combine                             0x00007fff4a6b185a $s7Combine16PublishedSubjectC7ConduitC5offeryyxF + 458
	17  Combine                             0x00007fff4a6b2627 $s7Combine16PublishedSubjectC4sendyyxFyAA11ConduitBaseCyxs5NeverOGXEfU_TA + 23
	18  Combine                             0x00007fff4a6e9df4 $s7Combine11ConduitListO7forEachyyyAA0B4BaseCyxq_GKXEKF + 196
	19  Combine                             0x00007fff4a6b13c8 $s7Combine16PublishedSubjectC4sendyyxF + 216
	20  Combine                             0x00007fff4a6d09ed $s7Combine9PublishedV18_enclosingInstance7wrapped7storagexqd___s24ReferenceWritableKeyPathCyqd__xGAHyqd__ACyxGGtcRld__CluisZTf4ngdgd_n + 221
	21  Combine                             0x00007fff4a6d02cb $s7Combine9PublishedV18_enclosingInstance7wrapped7storagexqd___s24ReferenceWritableKeyPathCyqd__xGAHyqd__ACyxGGtcRld__CluisZ + 27
	22  CombineCocoaTest                    0x000000010435d8e1 $s16CombineCocoaTest20SearchViewControllerC5valueSSSgvs + 145
	23  CombineCocoaTest                    0x000000010435d79a $s16CombineCocoaTest20SearchViewControllerC5valueSSSgvpACTk + 138
	24  libswiftCore.dylib                  0x00007fff2f222913 $ss26NonmutatingWritebackBufferCfD + 67
	25  libswiftCore.dylib                  0x00007fff2f421470 _swift_release_dealloc + 16
	26  Combine                             0x00007fff4a712737 $s7Combine11SubscribersO6AssignC7receiveyAC6DemandVq_F + 407
	27  Combine                             0x00007fff4a712a00 $s7Combine11SubscribersO6AssignCy_xq_GAA10SubscriberA2aGP7receiveyAC6DemandV5InputQzFTW + 16
	28  Combine                             0x00007fff4a72d7a5 $s7Combine10PublishersO11ConcatenateV5InnerC13suffixReceiveyAA11SubscribersO6DemandV6OutputQzF + 149
	29  Combine                             0x00007fff4a72d6ff $s7Combine10PublishersO11ConcatenateV5InnerC16SuffixSubscriberV7receiveyAA11SubscribersO6DemandV6OutputQzF + 15
	30  Combine                             0x00007fff4a72d981 $s7Combine10PublishersO11ConcatenateV5InnerC16SuffixSubscriberVy_xq__qd___GAA0F0A2aKP7receiveyAA11SubscribersO6DemandV5InputQzFTW + 17
	31  Combine                             0x00007fff4a735ce0 $s7Combine10PublishersO3MapV5Inner33_5A6CD15A64659A6248DAF677D4BB6188LLV7receiveyAA11SubscribersO6DemandV6OutputQzF + 144
	32  Combine                             0x00007fff4a735ce0 $s7Combine10PublishersO3MapV5Inner33_5A6CD15A64659A6248DAF677D4BB6188LLV7receiveyAA11SubscribersO6DemandV6OutputQzF + 144
	33  Combine                             0x00007fff4a6a8583 $s7Combine16AnySubscriberBoxC7receiveyAA11SubscribersO6DemandV5InputQzF + 35
	34  Combine                             0x00007fff4a6a9b32 $s7Combine13AnySubscriberV7receiveyAA11SubscribersO6DemandVxF + 18
	35  CombineCocoaTest                    0x0000000104376736 $s12CombineCocoa13DelegateProxyC26interceptSelectorPublishery0A003AnyG0VySayypGs5NeverOG10ObjectiveC0F0VFyAE0H10SubscriberVyAhJGcfU_yAHcfU_ + 70
	36  CombineCocoaTest                    0x000000010436ff6f $sSayypGIegg_AAytIegnr_TR + 15
	37  CombineCocoaTest                    0x00000001043762b1 $sSayypGIegg_AAytIegnr_TRTA + 17
	38  CombineCocoaTest                    0x000000010437601f $sSayypGytIegnr_AAIegg_TR + 63
	39  CombineCocoaTest                    0x0000000104375f78 $s12CombineCocoa13DelegateProxyC19interceptedSelector_9argumentsy10ObjectiveC0F0V_SayypGtF + 536
	40  CombineCocoaTest                    0x00000001043760e9 $s12CombineCocoa13DelegateProxyC19interceptedSelector_9argumentsy10ObjectiveC0F0V_SayypGtFTo + 105
	41  CombineCocoaTest                    0x00000001043790f3 -[ObjcDelegateProxy forwardInvocation:] + 115
	42  CoreFoundation                      0x00007fff2043e3f0 ___forwarding___ + 859
	43  CoreFoundation                      0x00007fff20440698 _CF_forwarding_prep_0 + 120
	44  UIFoundation                        0x00007fff23a13e16 -[NSTextStorage processEditing] + 316
	45  UIFoundation                        0x00007fff23a13a60 -[NSTextStorage endEditing] + 83
	46  UIFoundation                        0x00007fff23a13af9 -[NSTextStorage coordinateEditing:] + 53
	47  UIKitCore                           0x00007fff249d2071 -[UITextInputController _insertText:fromKeyboard:] + 395
	48  UIKitCore                           0x00007fff249d2cc8 -[UITextInputController insertText:] + 333
	49  UIKitCore                           0x00007fff249f58f5 -[UITextView insertText:] + 62
	50  UIKitCore                           0x00007fff24450cfe -[UIKeyboardImpl insertText:updateInputSource:] + 254
	51  UIKitCore                           0x00007fff2444a5c0 -[UIKeyboardImpl _performKeyboardOutput:shouldCheckDelegate:] + 1046
	52  UIKitCore                           0x00007fff2444a16a -[UIKeyboardImpl performKeyboardOutput:] + 25
	53  UIKitCore                           0x00007fff244491e7 __55-[UIKeyboardImpl handleKeyboardInput:executionContext:]_block_invoke_2 + 418
	54  UIKitCore                           0x00007fff2447bc3d -[UIKeyboardTaskEntry execute:] + 147
	55  UIKitCore                           0x00007fff2447a8d1 -[UIKeyboardTaskQueue continueExecutionOnMainThread] + 310
	56  Foundation                          0x00007fff2086f973 __NSThreadPerformPerform + 204
	57  CoreFoundation                      0x00007fff203a8845 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
	58  CoreFoundation                      0x00007fff203a873d __CFRunLoopDoSource0 + 180
	59  CoreFoundation                      0x00007fff203a7c1f __CFRunLoopDoSources0 + 248
	60  CoreFoundation                      0x00007fff203a23f7 __CFRunLoopRun + 878
	61  CoreFoundation                      0x00007fff203a1b9e CFRunLoopRunSpecific + 567
	62  GraphicsServices                    0x00007fff2b793db3 GSEventRunModal + 139
	63  UIKitCore                           0x00007fff2466d40f -[UIApplication _run] + 912
	64  UIKitCore                           0x00007fff24672320 UIApplicationMain + 101
	65  libswiftUIKit.dylib                 0x00007fff53c487b2 $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 98
	66  CombineCocoaTest                    0x000000010436026a $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 122
	67  CombineCocoaTest                    0x00000001043601de $s16CombineCocoaTest11AppDelegateC5$mainyyFZ + 46
	68  CombineCocoaTest                    0x00000001043602b9 main + 41
	69  libdyld.dylib                       0x00007fff20257409 start + 1
	70  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[NSLayoutManager _fillLayoutHoleForCharacterRange:desiredNumberOfLines:isSoft:] *** attempted layout while textStorage is editing.  It is not valid to cause the layoutManager to do layout while the textStorage is editing (ie the textStorage has been sent a beginEditing message without a matching endEditing.)'
terminating with uncaught exception of type NSException
CoreSimulator 732.17 - Device: iPhone 12 Pro (F1EB105F-0A1A-4AB4-91C9-728A05B22C85) - Runtime: iOS 14.1 (18A8394) - DeviceType: iPhone 12 Pro
(lldb) 

Collection view publishers should not have an effect before subscription

Describe the bug
simply referencing the willDisplayCellPublisher will change the delegate of your collection view. This should only happen After subscription.

    var willDisplayCellPublisher: AnyPublisher<(cell: UICollectionViewCell, indexPath: IndexPath), Never> {
        let selector = #selector(UICollectionViewDelegate.collectionView(_:willDisplay:forItemAt:))
        return delegateProxy.interceptSelectorPublisher(selector)
            .map { ($0[1] as! UICollectionViewCell, $0[2] as! IndexPath) }
            .eraseToAnyPublisher()
    }

UITextField textPublisher emitting twice

Describe the bug
I have come across a strange behaviour, where the textPublisher will emit the same value twice, if there is a subscription to it, and at the end of the subscription when the keyboard is dismissed (if it has not been dismissed before the subscription occurred).

To Reproduce
Imagine a save method that starts its chain by subscribing to the textPublisher, sending the value to an API, and on completion popping the view controller that contained the text field. The chain in the save method will be triggered twice, once when the method is invoked, and once when the view controller is popped, as that will cause the text field to dismiss the keyboard and emit an event (not sure which exactly) stating that editing has ended on it. I believe that this is due to the fact that the textPublisher observers both .allEditingEvents and .valueChanged events.

Expected behavior
I would expect the textPublisher to only emit when the actual text has changed, not when editing has ended or anything similar.

Device:

  • Probably not OS or device specific.
  • CombineCocoa 0.4.0

Combine Cocoa fails to archive with Xcode 13 RC

Describe the bug
When we try to archive a project which has CombineCocoa as a dependency, the archive fails. The following error is generated.
Instance method 'subscribe(on:options:)' requires that 'DispatchQueue' conform to 'Scheduler'
To Reproduce
Steps to reproduce the behavior:

  1. Add CombineCocoa as a dependency
  2. Archive a project

Expected behavior
The archive should be generated

Actual behavior
Getting the error
Instance method 'subscribe(on:options:)' requires that 'DispatchQueue' conform to 'Scheduler'

Screenshots
Screenshot 2021-09-20 at 7 47 52 PM

`didSelectItemPublisher` from collection view only pushes element to latest subscriber

Describe the bug
I had 2 subscribers subscribed to didSelectItemPublisher of collection view. One to open another controller, one to call api. But when I tapped on collection view cell, it just emited elements to the latest subscriber, ignored the previous one.

To Reproduce
Subscribe 2 subscribers to didSelectItemPublisher of collection view and see what happens

Expected behavior
didSelectItemPublisher emits to all its subscribers

Device:

  • Device: iPhone 11 pro
  • OS: macOS BigSur
  • CombineCocoa version: latest

UICollctionView did not work as expected. When I use colltionView to listen to both didScollPublish and didSelectedItemPublisher

UICollctionView did not work as expected. When I use colltionView to listen to both didScollPublish and didSelectedItemPublisher, they will not work at the same time and the first declaration will not work.

Simple case is as follows:

// NotWork
collectionView.didScrollPublisher.sink { [weak self] _ in
OMPrint("didScroll NotWork!" )
}
.store(in: &cancellables)

// Work
collectionView. DidSelectItemPublisher. Sink {indexPath in
OMPrint("didSelectItem Work!" )
}
.store(in: &cancellables)

When using UIScrollViewDelegateProxy and UICollectionViewDelegateProxy, one is ignored

Describe the bug
When using UIScrollViewDelegateProxy and UICollectionViewDelegateProxy, one is ignored

code

let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
self.collectionView.didSelectItemPublisher.sink { _ in
    print("not called")
}
.store(in: &self.cancellableSet)

self.collectionView.didEndDraggingPublisher.sink { _ in
    print("called")
}
.store(in: &self.cancellableSet)

Missing required module 'Runtime'

I've added CombineCocoa as an SPM dependency to an app being developed in Xcode 12 that supports iOS 13+.

When I add "import CombineCocoa" to a table view cell, it is highlighted in red and says "Missing required module 'Runtime'"

UIPageControl.currentPagePublisher is no longer working

Describe the bug
UIPageControl.currentPagePublisher is working as unexpected. It only emit the first value at all. This is debug message:

currentPagePublisher: receive subscription: ((extension in CombineCocoa):Combine.Publishers.ControlProperty<__C.UIPageControl, Swift.Int>.(unknown context at $1043e2a68).Subscription<Combine.Publishers.Print<Combine.AnyPublisher<Swift.Int, Swift.Never>>.(unknown context at $107462a60).Inner<Combine.Publishers.Map<Combine.Publishers.Print<Combine.AnyPublisher<Swift.Int, Swift.Never>>, Swift.Bool>.(unknown context at $10746bbe8).Inner<Combine.Publishers.RemoveDuplicates<Combine.Publishers.Map<Combine.Publishers.Print<Combine.AnyPublisher<Swift.Int, Swift.Never>>, Swift.Bool>>.(unknown context at $1074608c0).Inner<Combine.Subscribers.Sink<Swift.Bool, Swift.Never>>>>, __C.UIPageControl, Swift.Int>)
currentPagePublisher: request unlimited
currentPagePublisher: receive value: (0)

To Reproduce
Steps to reproduce the behavior:

  1. Create a UIPageControl
  2. Update currentPage of the UIPageControl, the indicator view is updated but currentPagePublisher emits nothing

Expected behavior
currentPagePublisher should emits current value

Device:

  • Device: [e.g. iPhone 11]
  • OS: [e.g. iOS 14.4]
  • CombineCocoa version: 0.2.2

Can't create my own delegate-based publishers

I'm trying to add some publishers to UISearchBarDelegate like this:

extension UISearchBar {
  var searchBarSearchButtonClicked: AnyPublisher<UISearchBar, Never> {
    let selector = #selector(UISearchBarDelegate.searchBarSearchButtonClicked(_:))

    return delegateProxy
      .interceptSelectorPublisher(selector)
      .map { $0[1] as! UISearchBar }
      .eraseToAnyPublisher()
  }

  private var delegateProxy: UISearchBarDelegateProxy {
      .createDelegateProxy(for: self)
  }
}

private class UISearchBarDelegateProxy: DelegateProxy, UISearchBarDelegate, DelegateProxyType {
  func setDelegate(to object: UISearchBar) {
    object.delegate = self
  }
}

Sadly I am getting two compiler errors:

'interceptSelectorPublisher' is inaccessible due to 'internal' protection level

and

Cannot inherit from non-open class 'DelegateProxy' outside of its defining module

Screen Shot 2020-10-01 at 13 50 29

UIBarButtonItem publisher

Have you considered adding a publisher for bar button item taps? Would be neat.

Iโ€™m happy to have a look at adding myself, just wanted to raise the issue to track.

Cocoapods installation

Installation via
pod 'CombineCocoa' -> instals old version 0.0.1 instead of 0.1.0
pod 'CombineCocoa', '~> 0.1.0' -> fails
[!] CocoaPods could not find compatible versions for pod "CombineCocoa": In Podfile: CombineCocoa (~> 0.1.0)
Only way to install version 0.1.0 is
pod 'CombineCocoa', :git => 'https://github.com/CombineCommunity/CombineCocoa.git', :tag => '0.1.0'

Cocoapods version:1.8.4

Using private handleEvent API

Describe the bug
I get an error while trying to upload a binary to Testflight

The app references non-public selectors in Payload/XXX.app/Frameworks/CombineCocoa.framework/CombineCocoa: handleEvent

To Reproduce
Steps to reproduce the behavior:

  1. Include CombineCocoa (using cocoapods in my case)
  2. Archive and upload to Testflight

Expected behavior
No error when distributing

Device:

  • XCode 14.0.1
  • CombineCocoa version 0.4.0

`reachedBottomPublisher` offset not working as expected.

Appears the UIScrollView.reachedBottomPublisher offset is not working as expected.

Currently the threshold is calculated by using max bracketing on offset of calculating the y to compare using visible height:

let threshold = max(offset, self.contentSize.height - visibleHeight)

However in order for this to work the publisher would have to be setup as:

collectionView
  .reachedBottomPublisher(collectionView.contentSize.height - visibleHeight - offset)
  .sink {

Which I don't believe is correct given when dynamically inserting content the content size will change.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.