diff --git a/ObserverSet.xcodeproj/project.pbxproj b/ObserverSet.xcodeproj/project.pbxproj
index 164d36f..ab18c77 100644
--- a/ObserverSet.xcodeproj/project.pbxproj
+++ b/ObserverSet.xcodeproj/project.pbxproj
@@ -162,7 +162,7 @@
attributes = {
LastSwiftMigration = 0720;
LastSwiftUpdateCheck = 0720;
- LastUpgradeCheck = 0610;
+ LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Mike Ash";
TargetAttributes = {
C2CC54581A71D8610084E87D = {
@@ -245,20 +245,32 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -276,6 +288,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
@@ -289,13 +302,23 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
@@ -304,6 +327,7 @@
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -313,6 +337,8 @@
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
@@ -331,6 +357,7 @@
INFOPLIST_FILE = ObserverSet/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.mikeash.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -350,6 +377,7 @@
INFOPLIST_FILE = ObserverSet/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.mikeash.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
@@ -369,6 +397,7 @@
);
INFOPLIST_FILE = ObserverSetTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.mikeash.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@@ -383,6 +412,7 @@
);
INFOPLIST_FILE = ObserverSetTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.mikeash.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
diff --git a/ObserverSet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ObserverSet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/ObserverSet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ObserverSet/Info.plist b/ObserverSet/Info.plist
index 8b33bc5..d0efcf2 100644
--- a/ObserverSet/Info.plist
+++ b/ObserverSet/Info.plist
@@ -7,7 +7,7 @@
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
- com.mikeash.$(PRODUCT_NAME:rfc1034identifier)
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
diff --git a/ObserverSet/ObserverSet.swift b/ObserverSet/ObserverSet.swift
index 84d5dae..f041ca4 100644
--- a/ObserverSet/ObserverSet.swift
+++ b/ObserverSet/ObserverSet.swift
@@ -8,52 +8,52 @@
import Foundation
-public class ObserverSetEntry {
- private weak var object: AnyObject?
- private let f: AnyObject -> Parameters -> Void
+public final class ObserverSetEntry {
- private init(object: AnyObject, f: AnyObject -> Parameters -> Void) {
+ fileprivate weak var object: AnyObject?
+ fileprivate let f: (AnyObject) -> (Parameters) -> Void
+
+ fileprivate init(object: AnyObject, f: @escaping (AnyObject) -> (Parameters) -> Void) {
self.object = object
self.f = f
}
}
-public class ObserverSet: CustomStringConvertible {
- // Locking support
+public final class ObserverSet: CustomStringConvertible {
- private var queue = dispatch_queue_create("com.mikeash.ObserverSet", nil)
+ private let queue = DispatchQueue(label: "com.mikeash.ObserverSet")
- private func synchronized(f: Void -> Void) {
- dispatch_sync(queue, f)
+ private func synchronized(_ f: () -> Void) {
+ queue.sync(execute: f)
}
-
- // Main implementation
-
private var entries: [ObserverSetEntry] = []
- public init() {}
+ public init() {
+ }
- public func add(object: T, _ f: T -> Parameters -> Void) -> ObserverSetEntry {
- let entry = ObserverSetEntry(object: object, f: { f($0 as! T) })
+ @discardableResult
+ public func add(_ object: T, _ f: @escaping (T) -> (Parameters) -> Void) -> ObserverSetEntry {
+ let entry = ObserverSetEntry(object: object, f: { f($0 as! T) }) // swiftlint:disable:this force_cast
synchronized {
self.entries.append(entry)
}
return entry
}
- public func add(f: Parameters -> Void) -> ObserverSetEntry {
- return self.add(self, { ignored in f })
+ @discardableResult
+ public func add(_ f: @escaping (Parameters) -> Void) -> ObserverSetEntry {
+ return add(self, { _ in f })
}
- public func remove(entry: ObserverSetEntry) {
+ public func remove(_ entry: ObserverSetEntry) {
synchronized {
self.entries = self.entries.filter{ $0 !== entry }
}
}
- public func notify(parameters: Parameters) {
- var toCall: [Parameters -> Void] = []
+ public func notify(_ parameters: Parameters) {
+ var toCall: [(Parameters) -> Void] = []
synchronized {
for entry in self.entries {
@@ -61,7 +61,7 @@ public class ObserverSet: CustomStringConvertible {
toCall.append(entry.f(object))
}
}
- self.entries = self.entries.filter{ $0.object != nil }
+ self.entries = self.entries.filter { $0.object != nil }
}
for f in toCall {
@@ -78,15 +78,20 @@ public class ObserverSet: CustomStringConvertible {
entries = self.entries
}
- let strings = entries.map{
- entry in
+ let strings = entries.map { entry in
(entry.object === self
? "\(entry.f)"
- : "\(entry.object) \(entry.f)")
+ : "\(String(describing: entry.object)) \(entry.f)")
}
- let joined = strings.joinWithSeparator(", ")
+ let joined = strings.joined(separator: ", ")
return "\(Mirror(reflecting: self).description): (\(joined))"
}
}
+extension ObserverSet where Parameters == Void {
+
+ public func notify() {
+ notify(()) // make the Swift 4 compiler happy
+ }
+}
diff --git a/ObserverSetTests/CaptureSemanticsTests.swift b/ObserverSetTests/CaptureSemanticsTests.swift
index 74c4066..ed85c98 100644
--- a/ObserverSetTests/CaptureSemanticsTests.swift
+++ b/ObserverSetTests/CaptureSemanticsTests.swift
@@ -19,9 +19,9 @@ class CaptureSemanticsTests: XCTestCase {
let observee = TestObservee()
init() {
- observee.event.add({ [weak self] () -> Void in
+ observee.event.add { [weak self] in
self?.foo()
- })
+ }
}
private func foo() {
@@ -32,10 +32,10 @@ class CaptureSemanticsTests: XCTestCase {
let observee = TestObservee()
init() {
- observee.event.add(self, self.dynamicType.voidHandler)
+ observee.event.add(self, type(of: self).voidHandler)
}
- func voidHandler() {
+ func voidHandler(_: Void) {
}
}
@@ -68,4 +68,4 @@ class CaptureSemanticsTests: XCTestCase {
XCTAssertNotNil(obj, "Registering a bound member function may result in a strong reference cycle. Use the overload of add() that takes an observer object and an unbound member function.")
}
-}
\ No newline at end of file
+}
diff --git a/ObserverSetTests/Info.plist b/ObserverSetTests/Info.plist
index e705997..ba72822 100644
--- a/ObserverSetTests/Info.plist
+++ b/ObserverSetTests/Info.plist
@@ -7,7 +7,7 @@
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
- com.mikeash.$(PRODUCT_NAME:rfc1034identifier)
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
diff --git a/ObserverSetTests/ObserverSetTests.swift b/ObserverSetTests/ObserverSetTests.swift
index 31f2d31..ac1cda0 100644
--- a/ObserverSetTests/ObserverSetTests.swift
+++ b/ObserverSetTests/ObserverSetTests.swift
@@ -12,6 +12,7 @@ import XCTest
import ObserverSet
class ObserverSetTests: XCTestCase {
+
class TestObservee {
let voidObservers = ObserverSet()
let stringObservers = ObserverSet()
@@ -31,20 +32,21 @@ class ObserverSetTests: XCTestCase {
}
class TestObserver {
+
init(observee: TestObservee) {
- observee.voidObservers.add(self, self.dynamicType.voidSent)
- observee.stringObservers.add(self, self.dynamicType.stringChanged)
- observee.twoStringObservers.add(self, self.dynamicType.twoStringChanged)
- observee.intObservers.add(self, self.dynamicType.intChanged)
- observee.intAndStringObservers.add(self, self.dynamicType.intAndStringChanged)
- observee.namedParameterObservers.add(self, self.dynamicType.namedParameterSent)
+ observee.voidObservers.add(self, type(of: self).voidSent)
+ observee.stringObservers.add(self, type(of: self).stringChanged)
+ observee.twoStringObservers.add(self, type(of: self).twoStringChanged)
+ observee.intObservers.add(self, type(of: self).intChanged)
+ observee.intAndStringObservers.add(self, type(of: self).intAndStringChanged)
+ observee.namedParameterObservers.add(self, type(of: self).namedParameterSent)
}
deinit {
print("deinit!!!!")
}
- func voidSent() {
+ func voidSent(_: Void) {
print("void sent")
}
@@ -52,20 +54,20 @@ class ObserverSetTests: XCTestCase {
print("stringChanged: " + s)
}
- func twoStringChanged(s1: String, s2: String) {
- print("twoStringChanged: \(s1) \(s2)")
+ func twoStringChanged(t: (s1: String, s2: String)) {
+ print("twoStringChanged: \(t.s1) \(t.s2)")
}
- func intChanged(i: Int, j: Int) {
- print("intChanged: \(i) \(j)")
+ func intChanged(t: (i: Int, j: Int)) {
+ print("intChanged: \(t.i) \(t.j)")
}
- func intAndStringChanged(i: Int, s: String) {
- print("intAndStringChanged: \(i) \(s)")
+ func intAndStringChanged(t :(i: Int, s: String)) {
+ print("intAndStringChanged: \(t.i) \(t.s)")
}
- func namedParameterSent(name: String, count: Int) {
- print("Named parameters: \(name) \(count)")
+ func namedParameterSent(t: (name: String, count: Int)) {
+ print("Named parameters: \(t.name) \(t.count)")
}
}
@@ -77,6 +79,7 @@ class ObserverSetTests: XCTestCase {
print("intAndStringObservers: \(observee.intAndStringObservers.description)")
observee.testNotify()
+ print("Destroying test observer \(String(describing: obj))")
obj = nil
observee.testNotify()
observee.intAndStringObservers.remove(token)