Skip to content

Commit 7e24a7a

Browse files
authored
Prepare 5.4.3 release (#254)
## [5.4.3] - 2021-08-13 ### Fixed - Fixed an issue where `304 NOT_MODIFIED` responses to SDK polling mode requests would be considered error responses. This could cause the completion on a `identify` request to not complete, and gave erroneous connection information data and logging output. - Fixed a crash when attempting to cache flag data containing variation JSON values containing a JSON `null` value nested within a JSON array.
1 parent 981f571 commit 7e24a7a

File tree

68 files changed

+1127
-2045
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1127
-2045
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
All notable changes to the LaunchDarkly iOS SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
44

5+
## [5.4.3] - 2021-08-13
6+
### Fixed
7+
- Fixed an issue where `304 NOT_MODIFIED` responses to SDK polling mode requests would be considered error responses. This could cause the completion on a `identify` request to not complete, and gave erroneous connection information data and logging output.
8+
- Fixed a crash when attempting to cache flag data containing variation JSON values containing a JSON `null` value nested within a JSON array.
9+
510
## [5.4.2] - 2021-06-17
611
### Fixed
712
- Avoid crash when `TimeInterval` configuration options are set to sufficiently large values. This was caused when converting these values to an `Int` value of milliseconds. (Thanks, [@delannoyk](https://github.com/launchdarkly/ios-client-sdk/pull/246)!)

LaunchDarkly.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Pod::Spec.new do |ld|
33

44
ld.name = "LaunchDarkly"
5-
ld.version = "5.4.2"
5+
ld.version = "5.4.3"
66
ld.summary = "iOS SDK for LaunchDarkly"
77

88
ld.description = <<-DESC

LaunchDarkly.xcodeproj/project.pbxproj

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
/* Begin PBXBuildFile section */
1010
830BF933202D188E006DF9B1 /* HTTPURLRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830BF932202D188E006DF9B1 /* HTTPURLRequest.swift */; };
11-
830DB3AA223409D800D65D25 /* URLCacheSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830DB3A9223409D800D65D25 /* URLCacheSpec.swift */; };
1211
830DB3AC22380A3E00D65D25 /* HTTPHeadersSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830DB3AB22380A3E00D65D25 /* HTTPHeadersSpec.swift */; };
1312
830DB3AE2239B54900D65D25 /* URLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830DB3AD2239B54900D65D25 /* URLResponse.swift */; };
1413
830DB3AF2239B54900D65D25 /* URLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830DB3AD2239B54900D65D25 /* URLResponse.swift */; };
@@ -373,7 +372,6 @@
373372

374373
/* Begin PBXFileReference section */
375374
830BF932202D188E006DF9B1 /* HTTPURLRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPURLRequest.swift; sourceTree = "<group>"; };
376-
830DB3A9223409D800D65D25 /* URLCacheSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLCacheSpec.swift; sourceTree = "<group>"; };
377375
830DB3AB22380A3E00D65D25 /* HTTPHeadersSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPHeadersSpec.swift; sourceTree = "<group>"; };
378376
830DB3AD2239B54900D65D25 /* URLResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLResponse.swift; sourceTree = "<group>"; };
379377
831188382113A16900D77CB5 /* LaunchDarkly_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LaunchDarkly_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -583,7 +581,6 @@
583581
83396BC81F7C3711000E256E /* DarklyServiceSpec.swift */,
584582
832307A51F7D8D720029815A /* URLRequestSpec.swift */,
585583
8392FFA22033565700320914 /* HTTPURLResponse.swift */,
586-
830DB3A9223409D800D65D25 /* URLCacheSpec.swift */,
587584
830DB3AB22380A3E00D65D25 /* HTTPHeadersSpec.swift */,
588585
);
589586
path = Networking;
@@ -708,14 +705,14 @@
708705
8354EFE61F263E4200C05156 /* Models */ = {
709706
isa = PBXGroup;
710707
children = (
711-
8354EFDD1F26380700C05156 /* LDConfig.swift */,
712-
83EBCB9E20D9A120003A7142 /* User */,
713-
83EBCB9D20D9A0A1003A7142 /* FeatureFlag */,
714-
8354EFDE1F26380700C05156 /* Event.swift */,
715-
83883DD4220B68A000EEAB95 /* ErrorObserver.swift */,
716708
8354AC5F224150C300CDE602 /* Cache */,
717709
C408884823033B7500420721 /* ConnectionInformation.swift */,
718710
B4C9D42D2489B5FF004A9B03 /* DiagnosticEvent.swift */,
711+
83883DD4220B68A000EEAB95 /* ErrorObserver.swift */,
712+
8354EFDE1F26380700C05156 /* Event.swift */,
713+
83EBCB9D20D9A0A1003A7142 /* FeatureFlag */,
714+
8354EFDD1F26380700C05156 /* LDConfig.swift */,
715+
83A2D6231F51CD7A00EA3BD4 /* LDUser.swift */,
719716
);
720717
path = Models;
721718
sourceTree = "<group>";
@@ -792,14 +789,6 @@
792789
path = FeatureFlag;
793790
sourceTree = "<group>";
794791
};
795-
83EBCB9E20D9A120003A7142 /* User */ = {
796-
isa = PBXGroup;
797-
children = (
798-
83A2D6231F51CD7A00EA3BD4 /* LDUser.swift */,
799-
);
800-
path = User;
801-
sourceTree = "<group>";
802-
};
803792
83EBCB9F20D9A143003A7142 /* FlagChange */ = {
804793
isa = PBXGroup;
805794
children = (
@@ -1474,7 +1463,6 @@
14741463
8335299E1FC37727001166F8 /* FlagMaintainingMock.swift in Sources */,
14751464
83383A5120460DD30024D975 /* SynchronizingErrorSpec.swift in Sources */,
14761465
8354AC6E22418C1F00CDE602 /* CacheableUserEnvironmentFlagsSpec.swift in Sources */,
1477-
830DB3AA223409D800D65D25 /* URLCacheSpec.swift in Sources */,
14781466
83B9A080204F56F4000C3F17 /* FlagChangeObserverSpec.swift in Sources */,
14791467
830DB3AC22380A3E00D65D25 /* HTTPHeadersSpec.swift in Sources */,
14801468
83D15235225299890054B6D4 /* DeprecatedCacheModelV2Spec.swift in Sources */,
@@ -1595,7 +1583,7 @@
15951583
GCC_C_LANGUAGE_STANDARD = gnu11;
15961584
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
15971585
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1598-
MARKETING_VERSION = 5.4.2;
1586+
MARKETING_VERSION = 5.4.3;
15991587
MODULEMAP_FILE = "";
16001588
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
16011589
PRODUCT_NAME = LaunchDarkly_tvOS;
@@ -1618,7 +1606,7 @@
16181606
GCC_C_LANGUAGE_STANDARD = gnu11;
16191607
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
16201608
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1621-
MARKETING_VERSION = 5.4.2;
1609+
MARKETING_VERSION = 5.4.3;
16221610
MODULEMAP_FILE = "";
16231611
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
16241612
PRODUCT_NAME = LaunchDarkly_tvOS;
@@ -1641,7 +1629,7 @@
16411629
GCC_C_LANGUAGE_STANDARD = gnu11;
16421630
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
16431631
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1644-
MARKETING_VERSION = 5.4.2;
1632+
MARKETING_VERSION = 5.4.3;
16451633
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
16461634
PRODUCT_NAME = LaunchDarkly_macOS;
16471635
SDKROOT = macosx;
@@ -1662,7 +1650,7 @@
16621650
GCC_C_LANGUAGE_STANDARD = gnu11;
16631651
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
16641652
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1665-
MARKETING_VERSION = 5.4.2;
1653+
MARKETING_VERSION = 5.4.3;
16661654
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
16671655
PRODUCT_NAME = LaunchDarkly_macOS;
16681656
SDKROOT = macosx;
@@ -1706,7 +1694,7 @@
17061694
CURRENT_PROJECT_VERSION = 1;
17071695
DEBUG_INFORMATION_FORMAT = dwarf;
17081696
DYLIB_COMPATIBILITY_VERSION = 5.4.0;
1709-
DYLIB_CURRENT_VERSION = 5.4.2;
1697+
DYLIB_CURRENT_VERSION = 5.4.3;
17101698
ENABLE_STRICT_OBJC_MSGSEND = YES;
17111699
ENABLE_TESTABILITY = YES;
17121700
FRAMEWORK_VERSION = B;
@@ -1777,7 +1765,7 @@
17771765
CURRENT_PROJECT_VERSION = 1;
17781766
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
17791767
DYLIB_COMPATIBILITY_VERSION = 5.4.0;
1780-
DYLIB_CURRENT_VERSION = 5.4.2;
1768+
DYLIB_CURRENT_VERSION = 5.4.3;
17811769
ENABLE_NS_ASSERTIONS = NO;
17821770
ENABLE_STRICT_OBJC_MSGSEND = YES;
17831771
FRAMEWORK_VERSION = B;
@@ -1816,7 +1804,7 @@
18161804
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
18171805
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
18181806
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
1819-
MARKETING_VERSION = 5.4.2;
1807+
MARKETING_VERSION = 5.4.3;
18201808
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
18211809
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
18221810
PRODUCT_NAME = LaunchDarkly;
@@ -1836,7 +1824,7 @@
18361824
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
18371825
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
18381826
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
1839-
MARKETING_VERSION = 5.4.2;
1827+
MARKETING_VERSION = 5.4.3;
18401828
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
18411829
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
18421830
PRODUCT_NAME = LaunchDarkly;
@@ -1878,7 +1866,7 @@
18781866
GCC_C_LANGUAGE_STANDARD = gnu11;
18791867
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
18801868
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1881-
MARKETING_VERSION = 5.4.2;
1869+
MARKETING_VERSION = 5.4.3;
18821870
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
18831871
PRODUCT_NAME = LaunchDarkly_watchOS;
18841872
SDKROOT = watchos;
@@ -1900,7 +1888,7 @@
19001888
GCC_C_LANGUAGE_STANDARD = gnu11;
19011889
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
19021890
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1903-
MARKETING_VERSION = 5.4.2;
1891+
MARKETING_VERSION = 5.4.3;
19041892
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
19051893
PRODUCT_NAME = LaunchDarkly_watchOS;
19061894
SDKROOT = watchos;

LaunchDarkly/GeneratedCode/mocks.generated.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
// Generated using Sourcery 0.16.1 — https://github.com/krzysztofzablocki/Sourcery
1+
// Generated using Sourcery 1.2.1 — https://github.com/krzysztofzablocki/Sourcery
22
// DO NOT EDIT
33

4-
54
import Foundation
65
import LDSwiftEventSource
76
@testable import LaunchDarkly
@@ -372,12 +371,19 @@ final class FlagChangeNotifyingMock: FlagChangeNotifying {
372371
notifyConnectionModeChangedObserversCallback?()
373372
}
374373

374+
var notifyUnchangedCallCount = 0
375+
var notifyUnchangedCallback: (() -> Void)?
376+
func notifyUnchanged() {
377+
notifyUnchangedCallCount += 1
378+
notifyUnchangedCallback?()
379+
}
380+
375381
var notifyObserversCallCount = 0
376382
var notifyObserversCallback: (() -> Void)?
377-
var notifyObserversReceivedArguments: (flagStore: FlagMaintaining, oldFlags: [LDFlagKey: FeatureFlag])?
378-
func notifyObservers(flagStore: FlagMaintaining, oldFlags: [LDFlagKey: FeatureFlag]) {
383+
var notifyObserversReceivedArguments: (oldFlags: [LDFlagKey: FeatureFlag], newFlags: [LDFlagKey: FeatureFlag])?
384+
func notifyObservers(oldFlags: [LDFlagKey: FeatureFlag], newFlags: [LDFlagKey: FeatureFlag]) {
379385
notifyObserversCallCount += 1
380-
notifyObserversReceivedArguments = (flagStore: flagStore, oldFlags: oldFlags)
386+
notifyObserversReceivedArguments = (oldFlags: oldFlags, newFlags: newFlags)
381387
notifyObserversCallback?()
382388
}
383389
}

LaunchDarkly/LaunchDarkly/Extensions/AnyComparer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import Foundation
1010
struct AnyComparer {
1111
private init() { }
1212

13-
//If editing this method to add classes here, update AnySpec with tests that verify the comparison for that class
14-
//swiftlint:disable:next cyclomatic_complexity
13+
// If editing this method to add classes here, update AnySpec with tests that verify the comparison for that class
14+
// swiftlint:disable:next cyclomatic_complexity
1515
static func isEqual(_ value: Any, to other: Any) -> Bool {
1616
switch (value, other) {
1717
case let (value, other) as (Bool, Bool):

LaunchDarkly/LaunchDarkly/Extensions/DateFormatter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ extension DateFormatter {
1212
let httpUrlHeaderFormatter = DateFormatter()
1313
httpUrlHeaderFormatter.locale = Locale(identifier: "en_US_POSIX")
1414
httpUrlHeaderFormatter.timeZone = TimeZone(abbreviation: "GMT")
15-
httpUrlHeaderFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz" //Mon, 07 May 2018 19:46:29 GMT
15+
httpUrlHeaderFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz" // Mon, 07 May 2018 19:46:29 GMT
1616

1717
return httpUrlHeaderFormatter
1818
}

LaunchDarkly/LaunchDarkly/Extensions/Dictionary.swift

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,33 @@ extension Dictionary where Key == String {
3838

3939
extension Dictionary where Key == String, Value == Any {
4040
var withNullValuesRemoved: [String: Any] {
41-
self.filter { !($1 is NSNull) }.mapValues { value in
41+
(self as [String: Any?]).compactMapValues { value in
42+
if value is NSNull {
43+
return nil
44+
}
4245
if let dictionary = value as? [String: Any] {
4346
return dictionary.withNullValuesRemoved
4447
}
48+
if let arr = value as? [Any] {
49+
return arr.withNullValuesRemoved
50+
}
51+
return value
52+
}
53+
}
54+
}
55+
56+
private extension Array where Element == Any {
57+
var withNullValuesRemoved: [Any] {
58+
(self as [Any?]).compactMap { value in
59+
if value is NSNull {
60+
return nil
61+
}
62+
if let arr = value as? [Any] {
63+
return arr.withNullValuesRemoved
64+
}
65+
if let dict = value as? [String: Any] {
66+
return dict.withNullValuesRemoved
67+
}
4568
return value
4669
}
4770
}

LaunchDarkly/LaunchDarkly/LDClient.swift

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,13 @@ public class LDClient {
126126
internalSetOnlineQueue.sync {
127127
guard goOnline, self.canGoOnline
128128
else {
129-
//go offline, which is not throttled
129+
// go offline, which is not throttled
130130
self.go(online: false, reasonOnlineUnavailable: self.reasonOnlineUnavailable(goOnline: goOnline), completion: completion)
131131
return
132132
}
133133

134134
self.throttler.runThrottled {
135-
//since going online was throttled, check the last called setOnline value and whether we can go online
135+
// since going online was throttled, check the last called setOnline value and whether we can go online
136136
self.go(online: goOnline && self.canGoOnline, reasonOnlineUnavailable: self.reasonOnlineUnavailable(goOnline: goOnline), completion: completion)
137137
}
138138
}
@@ -269,6 +269,7 @@ public class LDClient {
269269
}
270270

271271
let config: LDConfig
272+
let service: DarklyServiceProvider
272273
private(set) var user: LDUser
273274

274275
/**
@@ -310,6 +311,7 @@ public class LDClient {
310311
flagStore.replaceStore(newFlags: user.flagStore?.featureFlags ?? [:], completion: nil)
311312
}
312313
self.service.user = self.user
314+
self.service.clearFlagResponseCache()
313315
flagSynchronizer = serviceFactory.makeFlagSynchronizer(streamingMode: ConnectionInformation.effectiveStreamingMode(config: config, ldClient: self),
314316
pollingInterval: config.flagPollingInterval(runMode: runMode),
315317
useReport: config.useReport,
@@ -325,15 +327,11 @@ public class LDClient {
325327
if !config.autoAliasingOptOut && previousUser.isAnonymous && !newUser.isAnonymous {
326328
self.alias(context: newUser, previousContext: previousUser)
327329
}
328-
329-
self.service.clearFlagResponseCache()
330330
}
331331
}
332332

333333
private let internalIdentifyQueue: DispatchQueue = DispatchQueue(label: "InternalIdentifyQueue")
334334

335-
let service: DarklyServiceProvider
336-
337335
// MARK: Retrieving Flag Values
338336

339337
/**
@@ -375,7 +373,7 @@ public class LDClient {
375373
*/
376374
/// - Tag: variationWithdefaultValue
377375
public func variation<T: LDFlagValueConvertible>(forKey flagKey: LDFlagKey, defaultValue: T) -> T {
378-
//the defaultValue cast to 'as T?' directs the call to the Optional-returning variation method
376+
// the defaultValue cast to 'as T?' directs the call to the Optional-returning variation method
379377
variation(forKey: flagKey, defaultValue: defaultValue as T?) ?? defaultValue
380378
}
381379

@@ -694,6 +692,9 @@ public class LDClient {
694692
self.updateCacheAndReportChanges(user: self.user, oldFlags: oldFlags)
695693
}
696694
}
695+
case .upToDate:
696+
connectionInformation.lastKnownFlagValidity = Date()
697+
flagChangeNotifier.notifyUnchanged()
697698
case .error(let synchronizingError):
698699
process(synchronizingError, logPrefix: typeName(and: #function, appending: ": "))
699700
}
@@ -713,7 +714,7 @@ public class LDClient {
713714
private func updateCacheAndReportChanges(user: LDUser,
714715
oldFlags: [LDFlagKey: FeatureFlag]) {
715716
flagCache.storeFeatureFlags(flagStore.featureFlags, userKey: user.key, mobileKey: config.mobileKey, lastUpdated: Date(), storeMode: .async)
716-
flagChangeNotifier.notifyObservers(flagStore: flagStore, oldFlags: oldFlags)
717+
flagChangeNotifier.notifyObservers(oldFlags: oldFlags, newFlags: flagStore.featureFlags)
717718
}
718719

719720
// MARK: Events
@@ -790,7 +791,7 @@ public class LDClient {
790791
Log.debug(typeName(and: #function) + "result: \(result)")
791792
switch result {
792793
case .success:
793-
break //EventReporter handles removing events from the event store, so there's nothing to do here. It's here in case we want to do something in the future.
794+
break // EventReporter handles removing events from the event store, so there's nothing to do here. It's here in case we want to do something in the future.
794795
case .error(let synchronizingError):
795796
process(synchronizingError, logPrefix: typeName(and: #function, appending: ": "))
796797
}
@@ -828,8 +829,6 @@ public class LDClient {
828829
return
829830
}
830831

831-
HTTPHeaders.removeFlagRequestEtags()
832-
833832
let internalUser = user
834833

835834
LDClient.instances = [:]

LaunchDarkly/LaunchDarkly/LDCommon.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@
77

88
import Foundation
99

10-
///The feature flag key is a String. This typealias helps define where the SDK expects the string to be a feature flag key.
10+
/// The feature flag key is a String. This typealias helps define where the SDK expects the string to be a feature flag key.
1111
public typealias LDFlagKey = String
1212

13-
///An object can own an observer for as long as the object exists. Swift structs and enums cannot be observer owners.
13+
/// An object can own an observer for as long as the object exists. Swift structs and enums cannot be observer owners.
1414
public typealias LDObserverOwner = AnyObject
15-
///A closure used to notify an observer owner of a change to a single feature flag's value.
15+
/// A closure used to notify an observer owner of a change to a single feature flag's value.
1616
public typealias LDFlagChangeHandler = (LDChangedFlag) -> Void
17-
///A closure used to notify an observer owner of a change to the feature flags in a collection of `LDChangedFlag`.
17+
/// A closure used to notify an observer owner of a change to the feature flags in a collection of `LDChangedFlag`.
1818
public typealias LDFlagCollectionChangeHandler = ([LDFlagKey: LDChangedFlag]) -> Void
19-
///A closure used to notify an observer owner that a feature flag request resulted in no changes to any feature flag.
19+
/// A closure used to notify an observer owner that a feature flag request resulted in no changes to any feature flag.
2020
public typealias LDFlagsUnchangedHandler = () -> Void
21-
///A closure used to notify an observer owner that the current connection mode has changed.
21+
/// A closure used to notify an observer owner that the current connection mode has changed.
2222
public typealias LDConnectionModeChangedHandler = (ConnectionInformation.ConnectionMode) -> Void
23-
///A closure used to notify an observer owner that an error occurred during feature flag processing.
23+
/// A closure used to notify an observer owner that an error occurred during feature flag processing.
2424
public typealias LDErrorHandler = (Error) -> Void
2525

2626
extension LDFlagKey {

0 commit comments

Comments
 (0)