Skip to content
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)
}

}