Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Observable property wrapper #25

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
12 changes: 8 additions & 4 deletions Hanson.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
857451EC235A360500473D97 /* ObservablePropertyWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 857451EB235A360400473D97 /* ObservablePropertyWrapperTests.swift */; };
C8237A5C1ED82978003279DB /* NotificationObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8237A5B1ED82978003279DB /* NotificationObservable.swift */; };
C8237A5E1ED82BBA003279DB /* NotificationObservableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8237A5D1ED82BBA003279DB /* NotificationObservableTests.swift */; };
C8888E841E9CCA7C00803644 /* Bindable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8888E741E9CCA7C00803644 /* Bindable.swift */; };
Expand Down Expand Up @@ -43,6 +44,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
857451EB235A360400473D97 /* ObservablePropertyWrapperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObservablePropertyWrapperTests.swift; sourceTree = "<group>"; };
C8237A5B1ED82978003279DB /* NotificationObservable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationObservable.swift; sourceTree = "<group>"; };
C8237A5D1ED82BBA003279DB /* NotificationObservableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationObservableTests.swift; sourceTree = "<group>"; };
C8888E741E9CCA7C00803644 /* Bindable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bindable.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -174,12 +176,13 @@
isa = PBXGroup;
children = (
C8DBC7601E3A4E2E0028E936 /* Helpers */,
C8DBC7541E3A4E170028E936 /* ObservationManagerTests.swift */,
C8DBC7531E3A4E170028E936 /* EventPublisherTests.swift */,
C8DBC7551E3A4E170028E936 /* ObservableTests.swift */,
C8EB01DB1E435A0F0036E3C9 /* CustomBindableTests.swift */,
C8DBC7521E3A4E170028E936 /* DynamicObservableTests.swift */,
C8DBC7531E3A4E170028E936 /* EventPublisherTests.swift */,
C8237A5D1ED82BBA003279DB /* NotificationObservableTests.swift */,
C8EB01DB1E435A0F0036E3C9 /* CustomBindableTests.swift */,
857451EB235A360400473D97 /* ObservablePropertyWrapperTests.swift */,
C8DBC7551E3A4E170028E936 /* ObservableTests.swift */,
C8DBC7541E3A4E170028E936 /* ObservationManagerTests.swift */,
C8DBC72B1E3A47370028E936 /* Info.plist */,
);
path = HansonTests;
Expand Down Expand Up @@ -335,6 +338,7 @@
C8DBC7641E3A4E2E0028E936 /* TestEventPublisher.swift in Sources */,
C8DBC75B1E3A4E170028E936 /* ObservationManagerTests.swift in Sources */,
C8DBC7631E3A4E2E0028E936 /* TestObject.swift in Sources */,
857451EC235A360500473D97 /* ObservablePropertyWrapperTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
15 changes: 15 additions & 0 deletions Hanson/Observable/Observable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Foundation

/// The `Observable` class represents a value that can be observed for changes.
/// When changing the observable's value, the observable will publish a `ValueChange` event with the old and new value.
@propertyWrapper
public class Observable<Value>: EventPublisher, Bindable {

/// An alias for the event type that the observable publishes.
Expand All @@ -22,8 +23,22 @@ public class Observable<Value>: EventPublisher, Bindable {
_value = value
}

/// Initializes the observable through a propertyWrapper's initial value assignment.
///
/// - Parameter value: The observable's initial value.
public init(wrappedValue value: Value) {
_value = value
}

// MARK: Value

/// The wrapped value of the observable as accessed through the propertyWrapper.
/// When setting this to a new value, the observable will publish a `ValueChange` event with the old and new value.
public var wrappedValue: Value {
get { return value }
set { value = newValue }
}

/// The value of the observable. When setting this to a new value, the observable will publish a `ValueChange` event with the old and new value.
public var value: Value {
get {
Expand Down
71 changes: 71 additions & 0 deletions HansonTests/ObservablePropertyWrapperTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// ObservablePropertyWrapperTests.swift
// HansonTests
//
// Created by Niklas Holloh on 26.07.19.
// Copyright © 2019 Blendle. All rights reserved.
//

import XCTest
@testable import Hanson

class ObservablePropertyWrapperTests: XCTestCase {

@Observable var value = "Hello World"

func testObservingValue() {
var lastEvent: ValueChange<String>!
_value.addEventHandler { event in
lastEvent = event
}

// Verify that changing the value publishes an event with the old and new value.
value = "New Value"
XCTAssertEqual(lastEvent.oldValue, "Hello World")
XCTAssertEqual(lastEvent.newValue, "New Value")

value = "Some Other Value"
XCTAssertEqual(lastEvent.oldValue, "New Value")
XCTAssertEqual(lastEvent.newValue, "Some Other Value")
}

func testSilentlyUpdatingValue() {
var lastEvent: ValueChange<String>!
_value.addEventHandler { event in
lastEvent = event
}

// Verify that changing the value works via the silently update function.
_value.silentlyUpdateValue(to: "New Value")
XCTAssertEqual(value, "New Value")

// Verify that no event has been published.
XCTAssertNil(lastEvent)

}

func testUpdatingValueOnMultipleQueues() {
var numberOfEvents = 0
_value.addEventHandler { _ in
numberOfEvents += 1
}

// Update the value 100 times on different queues.
for i in 0..<100 {
let valueExpectation = expectation(description: "Updated value")

let queue = DispatchQueue(label: "com.blendle.hanson.tests.observable.queue\(i)")
queue.async {
self.value = "New Value"

valueExpectation.fulfill()
}
}

waitForExpectations(timeout: 10, handler: nil)

// Verify that the value has been updated 100 times.
XCTAssertEqual(numberOfEvents, 100)
}

}