Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ Pods/
# Add this line if you want to avoid checking in source code from Carthage dependencies.
Carthage/Checkouts
Carthage/Build

# MacOS
#
.DS_Store
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Changelog
Current master
--------------

- Move to a new protocol-based approach, allowing non-reference types to use the library 🎉 See [#41](https://github.com/RxSwiftCommunity/NSObject-Rx/pull/41) - [@twittemb](https://github.com/twittemb)
- Removes `rx_disposeBag` in favour of `rx.disposeBag`.

2.3.0
-----
- Make rx.disposeBag read/write ([#40](https://github.com/RxSwiftCommunity/NSObject-Rx/pull/40)) - [@freak4pc](https://github.com/freak4pc)
Expand Down
23 changes: 21 additions & 2 deletions Demo/Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
4782C2FD3F28267D0A736242 /* Pods_DemoTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98ABDE1166974D890C0D32DA /* Pods_DemoTests.framework */; };
5E6ACB541F5863D30050E957 /* ProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E6ACB531F5863D30050E957 /* ProtocolTests.swift */; };
5E9E831F1BF79B3000C85B46 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9E831E1BF79B3000C85B46 /* AppDelegate.swift */; };
5E9E83211BF79B3000C85B46 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9E83201BF79B3000C85B46 /* ViewController.swift */; };
5E9E83241BF79B3000C85B46 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5E9E83221BF79B3000C85B46 /* Main.storyboard */; };
Expand All @@ -31,6 +32,7 @@
1E9B7B66986C52EC97B65AAF /* Pods-Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig"; sourceTree = "<group>"; };
371C581F5871A4EEFB5D8274 /* Pods-DemoTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-DemoTests/Pods-DemoTests.release.xcconfig"; sourceTree = "<group>"; };
579EF2C5ACCE845BC7962A04 /* Pods-Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-Demo/Pods-Demo.release.xcconfig"; sourceTree = "<group>"; };
5E6ACB531F5863D30050E957 /* ProtocolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProtocolTests.swift; sourceTree = "<group>"; };
5E9E831B1BF79B3000C85B46 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
5E9E831E1BF79B3000C85B46 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
5E9E83201BF79B3000C85B46 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -104,6 +106,7 @@
children = (
5E9E83331BF79B3000C85B46 /* DemoTests.swift */,
5E9E83351BF79B3000C85B46 /* Info.plist */,
5E6ACB531F5863D30050E957 /* ProtocolTests.swift */,
);
path = DemoTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -251,13 +254,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Demo-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9FB93DCD00D21C3B467F9BEF /* [CP] Copy Pods Resources */ = {
Expand Down Expand Up @@ -296,13 +302,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-DemoTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
FFDE61183A484AA609E96F39 /* [CP] Embed Pods Frameworks */ = {
Expand All @@ -311,9 +320,18 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-DemoTests/Pods-DemoTests-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/NSObject+Rx/NSObject_Rx.framework",
"${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework",
"${BUILT_PRODUCTS_DIR}/Quick/Quick.framework",
"${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NSObject_Rx.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand All @@ -337,6 +355,7 @@
buildActionMask = 2147483647;
files = (
5E9E83341BF79B3000C85B46 /* DemoTests.swift in Sources */,
5E6ACB541F5863D30050E957 /* ProtocolTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
8 changes: 4 additions & 4 deletions Demo/DemoTests/DemoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import NSObject_Rx
class Test: QuickSpec {
override func spec() {
it("respects setter") {
let subject = NSObject()
var subject = NSObject()
let disposeBag = DisposeBag()
subject.rx_disposeBag = disposeBag
subject.rx.disposeBag = disposeBag

expect(subject.rx_disposeBag) === disposeBag
expect(subject.rx.disposeBag) === disposeBag
}

it("diposes when object is deallocated") {
Expand All @@ -22,7 +22,7 @@ class Test: QuickSpec {
let subject = NSObject()
variable.subscribe(onNext: { _ in
executed = true
}).addDisposableTo(subject.rx_disposeBag)
}).addDisposableTo(subject.rx.disposeBag)
}

// Force a new value through the subscription to test its been disposed of.
Expand Down
45 changes: 45 additions & 0 deletions Demo/DemoTests/ProtocolTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import XCTest
import RxSwift
@testable import NSObject_Rx

class MockNSObject: NSObject {
}

class DisposableObject: HasDisposeBag {
}

class NSObject_RxTests: XCTestCase {

private var mockNSObject: MockNSObject!
private var disposableObject: DisposableObject!

override func setUp() {
super.setUp()
self.mockNSObject = MockNSObject()
self.disposableObject = DisposableObject()
}

override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}

func testNSObject() {
XCTAssertNotNil(self.mockNSObject.rx.disposeBag)
let newDisposeBag = DisposeBag()
self.mockNSObject.rx.disposeBag = newDisposeBag
let address1 = Unmanaged<AnyObject>.passUnretained(self.mockNSObject.rx.disposeBag as AnyObject).toOpaque()
let address2 = Unmanaged<AnyObject>.passUnretained(newDisposeBag as AnyObject).toOpaque()
XCTAssert(address1 == address2)
}

func testDisposeBagable() {
XCTAssertNotNil(self.disposableObject.disposeBag)
let newDisposeBag = DisposeBag()
self.disposableObject.disposeBag = newDisposeBag
let address1 = Unmanaged<AnyObject>.passUnretained(self.disposableObject.disposeBag as AnyObject).toOpaque()
let address2 = Unmanaged<AnyObject>.passUnretained(newDisposeBag as AnyObject).toOpaque()
XCTAssert(address1 == address2)
}
}

10 changes: 5 additions & 5 deletions Demo/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PODS:
- Nimble (6.1.0)
- NSObject+Rx (2.2.0):
- RxSwift
- NSObject+Rx (2.3.0):
- RxSwift (~> 3.0)
- Quick (1.1.0)
- RxSwift (3.0.1)

Expand All @@ -13,14 +13,14 @@ DEPENDENCIES:

EXTERNAL SOURCES:
NSObject+Rx:
:path: "../"
:path: ../

SPEC CHECKSUMS:
Nimble: c53e6903fee94041b90ded74f135820437d8bf59
NSObject+Rx: be98a305d3c488a7b8da6fc38c0c64aba70514cf
NSObject+Rx: a73d1851aede1776223a4543025dc25a001e8b2a
Quick: dafc587e21eed9f4cab3249b9f9015b0b7a7f71d
RxSwift: af5680055c4ad04480189c52d28385b1029493a6

PODFILE CHECKSUM: 0505237e77e025183988e56cdaa4bb98c27d03ba

COCOAPODS: 1.2.1
COCOAPODS: 1.3.0.beta.2
53 changes: 53 additions & 0 deletions DisposeBagable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// DisposeBagable.swift
// NSObject-Rx
//
// Created by Thibault Wittemberg on 2017-08-25.
// Copyright © 2017 RxSwiftCommunity. All rights reserved.
//

import Foundation
import RxSwift
import ObjectiveC

fileprivate struct AssociatedKeys {
static var disposeBag = "disposeBag"
}

/// each DisposeBagable offers a unique Rx DisposeBag instance
public protocol HasDisposeBag {

/// a unique Rx DisposeBag instance
var disposeBag: DisposeBag { get set }
}

extension HasDisposeBag {

private func doLocked(forClosure closure: () -> Void) {
objc_sync_enter(self); defer { objc_sync_exit(self) }
closure()
}

public var disposeBag: DisposeBag {
get {
var rxDisposeBag: DisposeBag!
doLocked {
let lookup = objc_getAssociatedObject(self, &AssociatedKeys.disposeBag) as? DisposeBag
if let lookup = lookup {
rxDisposeBag = lookup
} else {
let newDisposeBag = DisposeBag()
objc_setAssociatedObject(self, &AssociatedKeys.disposeBag, newDisposeBag, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
rxDisposeBag = newDisposeBag
}
}
return rxDisposeBag
}

set {
doLocked {
objc_setAssociatedObject(self, &AssociatedKeys.disposeBag, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}
42 changes: 8 additions & 34 deletions NSObject+Rx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,17 @@ import Foundation
import RxSwift
import ObjectiveC

public extension NSObject {
fileprivate struct AssociatedKeys {
static var DisposeBag = "rx_disposeBag"
}

fileprivate func doLocked(_ closure: () -> Void) {
objc_sync_enter(self); defer { objc_sync_exit(self) }
closure()
}
extension NSObject: HasDisposeBag {
}

var rx_disposeBag: DisposeBag {
get {
var disposeBag: DisposeBag!
doLocked {
let lookup = objc_getAssociatedObject(self, &AssociatedKeys.DisposeBag) as? DisposeBag
if let lookup = lookup {
disposeBag = lookup
} else {
let newDisposeBag = DisposeBag()
self.rx_disposeBag = newDisposeBag
disposeBag = newDisposeBag
}
}
return disposeBag
}
public extension Reactive where Base: HasDisposeBag {

/// a unique DisposeBag that is related to the Reactive.Base instance
var disposeBag: DisposeBag {
get { return base.disposeBag }
set {
doLocked {
objc_setAssociatedObject(self, &AssociatedKeys.DisposeBag, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
var mutableBase = base
mutableBase.disposeBag = newValue
}
}
}

public extension Reactive where Base: NSObject {
var disposeBag: DisposeBag {
get { return base.rx_disposeBag }
set { base.rx_disposeBag = newValue }
}
}
Loading