Skip to content

Commit 89d87b2

Browse files
tanderson-ldbwoskow-ldtorchhoundgwhelanLDlouis-launchdarkly
authored
prepare 8.3.1 release (#318)
## [8.3.1] - 2023-10-31 ### Changed: - Calling `identify()` with the current context is now more efficient and no longer results in re-establishing a connection. ### Fixed: - Fixed issue where flag change listeners were not being triggered when `identify()` was called. --------- Co-authored-by: Ben Woskow <[email protected]> Co-authored-by: torchhound <[email protected]> Co-authored-by: Gavin Whelan <[email protected]> Co-authored-by: Louis Chan <[email protected]> Co-authored-by: Matthew Keeler <[email protected]> Co-authored-by: Louis Chan <[email protected]> Co-authored-by: Ember Stevens <[email protected]> Co-authored-by: Ember Stevens <[email protected]> Co-authored-by: Ryan Lamb <[email protected]> Co-authored-by: ld-repository-standards[bot] <113625520+ld-repository-standards[bot]@users.noreply.github.com> Co-authored-by: Kane Parkinson <[email protected]>
1 parent 89f5d3e commit 89d87b2

File tree

10 files changed

+117
-18
lines changed

10 files changed

+117
-18
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
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+
## [8.3.1] - 2023-10-31
6+
### Changed:
7+
- Calling `identify()` with the current context is now more efficient and no longer results in re-establishing a connection.
8+
9+
### Fixed:
10+
- Fixed issue where flag change listeners were not being triggered when `identify()` was called.
11+
512
## [8.3.0] - 2023-09-08
613
### Changed:
714
- Deprecated `LDValue.init(integerLiteral: Double)` as this method signature is misleading. A new `LDValue.init(integerLiteral: Int)` signature has been added for clarity.

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 = "8.3.0"
5+
ld.version = "8.3.1"
66
ld.summary = "iOS SDK for LaunchDarkly"
77

88
ld.description = <<-DESC

LaunchDarkly.xcodeproj/project.pbxproj

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,7 +1503,7 @@
15031503
GCC_C_LANGUAGE_STANDARD = gnu11;
15041504
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
15051505
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1506-
MARKETING_VERSION = 8.3.0;
1506+
MARKETING_VERSION = 8.3.1;
15071507
MODULEMAP_FILE = "";
15081508
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
15091509
PRODUCT_NAME = LaunchDarkly_tvOS;
@@ -1526,7 +1526,7 @@
15261526
GCC_C_LANGUAGE_STANDARD = gnu11;
15271527
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
15281528
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1529-
MARKETING_VERSION = 8.3.0;
1529+
MARKETING_VERSION = 8.3.1;
15301530
MODULEMAP_FILE = "";
15311531
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
15321532
PRODUCT_NAME = LaunchDarkly_tvOS;
@@ -1549,7 +1549,7 @@
15491549
GCC_C_LANGUAGE_STANDARD = gnu11;
15501550
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
15511551
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1552-
MARKETING_VERSION = 8.3.0;
1552+
MARKETING_VERSION = 8.3.1;
15531553
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
15541554
PRODUCT_NAME = LaunchDarkly_macOS;
15551555
SDKROOT = macosx;
@@ -1570,7 +1570,7 @@
15701570
GCC_C_LANGUAGE_STANDARD = gnu11;
15711571
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
15721572
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1573-
MARKETING_VERSION = 8.3.0;
1573+
MARKETING_VERSION = 8.3.1;
15741574
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
15751575
PRODUCT_NAME = LaunchDarkly_macOS;
15761576
SDKROOT = macosx;
@@ -1614,7 +1614,7 @@
16141614
CURRENT_PROJECT_VERSION = 1;
16151615
DEBUG_INFORMATION_FORMAT = dwarf;
16161616
DYLIB_COMPATIBILITY_VERSION = 8.0.0;
1617-
DYLIB_CURRENT_VERSION = 8.3.0;
1617+
DYLIB_CURRENT_VERSION = 8.3.1;
16181618
ENABLE_STRICT_OBJC_MSGSEND = YES;
16191619
ENABLE_TESTABILITY = YES;
16201620
FRAMEWORK_VERSION = E;
@@ -1685,7 +1685,7 @@
16851685
CURRENT_PROJECT_VERSION = 1;
16861686
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
16871687
DYLIB_COMPATIBILITY_VERSION = 8.0.0;
1688-
DYLIB_CURRENT_VERSION = 8.3.0;
1688+
DYLIB_CURRENT_VERSION = 8.3.1;
16891689
ENABLE_NS_ASSERTIONS = NO;
16901690
ENABLE_STRICT_OBJC_MSGSEND = YES;
16911691
FRAMEWORK_VERSION = E;
@@ -1724,7 +1724,7 @@
17241724
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
17251725
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
17261726
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
1727-
MARKETING_VERSION = 8.3.0;
1727+
MARKETING_VERSION = 8.3.1;
17281728
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
17291729
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
17301730
PRODUCT_NAME = LaunchDarkly;
@@ -1744,7 +1744,7 @@
17441744
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
17451745
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
17461746
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
1747-
MARKETING_VERSION = 8.3.0;
1747+
MARKETING_VERSION = 8.3.1;
17481748
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
17491749
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
17501750
PRODUCT_NAME = LaunchDarkly;
@@ -1786,7 +1786,7 @@
17861786
GCC_C_LANGUAGE_STANDARD = gnu11;
17871787
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
17881788
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1789-
MARKETING_VERSION = 8.3.0;
1789+
MARKETING_VERSION = 8.3.1;
17901790
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
17911791
PRODUCT_NAME = LaunchDarkly_watchOS;
17921792
SDKROOT = watchos;
@@ -1808,7 +1808,7 @@
18081808
GCC_C_LANGUAGE_STANDARD = gnu11;
18091809
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
18101810
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1811-
MARKETING_VERSION = 8.3.0;
1811+
MARKETING_VERSION = 8.3.1;
18121812
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
18131813
PRODUCT_NAME = LaunchDarkly_watchOS;
18141814
SDKROOT = watchos;

LaunchDarkly/LaunchDarkly/LDClient.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,21 @@ public class LDClient {
303303

304304
func internalIdentify(newContext: LDContext, completion: (() -> Void)? = nil) {
305305
internalIdentifyQueue.sync {
306+
if self.context == newContext {
307+
self.eventReporter.record(IdentifyEvent(context: self.context))
308+
completion?()
309+
return
310+
}
311+
306312
self.context = newContext
307313
Log.debug(self.typeName(and: #function) + "new context set with key: " + self.context.fullyQualifiedKey() )
308314
let wasOnline = self.isOnline
309315
self.internalSetOnline(false)
310316

311317
let cachedContextFlags = self.flagCache.retrieveFeatureFlags(contextKey: self.context.fullyQualifiedHashedKey()) ?? [:]
318+
let oldItems = flagStore.storedItems.featureFlags
312319
flagStore.replaceStore(newStoredItems: cachedContextFlags)
320+
flagChangeNotifier.notifyObservers(oldFlags: oldItems, newFlags: flagStore.storedItems.featureFlags)
313321
self.service.context = self.context
314322
self.service.clearFlagResponseCache()
315323
flagSynchronizer = serviceFactory.makeFlagSynchronizer(streamingMode: ConnectionInformation.effectiveStreamingMode(config: config, ldClient: self),

LaunchDarkly/LaunchDarkly/Models/Context/Reference.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ extension ReferenceError: CustomStringConvertible {
8787
/// - Reference("name") or Reference("/name") would refer to the value "xyz"
8888
/// - Reference("/address/street") would refer to the value "99 Main St."
8989
/// - Reference("a/b") or Reference("/a~1b") would refer to the value "ok"
90-
public struct Reference: Codable, Equatable, Hashable {
90+
public struct Reference: Codable, Hashable {
9191
private var error: ReferenceError?
9292
private var rawPath: String
9393
private var components: [String] = []
@@ -230,3 +230,9 @@ public struct Reference: Codable, Equatable, Hashable {
230230
return self.components[index]
231231
}
232232
}
233+
234+
extension Reference: Equatable {
235+
public static func == (lhs: Reference, rhs: Reference) -> Bool {
236+
return lhs.error == rhs.error && lhs.components == rhs.components
237+
}
238+
}

LaunchDarkly/LaunchDarkly/ServiceObjects/EnvironmentReporter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ struct EnvironmentReporter: EnvironmentReporting {
102102
#endif
103103

104104
var shouldThrottleOnlineCalls: Bool { !isDebugBuild }
105-
let sdkVersion = "8.3.0"
105+
let sdkVersion = "8.3.1"
106106
// Unfortunately, the following does not function in certain configurations, such as when included through SPM
107107
// var sdkVersion: String {
108108
// Bundle(for: LDClient.self).infoDictionary?["CFBundleShortVersionString"] as? String ?? "5.x"

LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,24 @@ final class LDClientSpec: QuickSpec {
592592
expect(testContext.flagStoreMock.replaceStoreCallCount) == 1
593593
expect(testContext.flagStoreMock.replaceStoreReceivedNewFlags) == stubFlags
594594
}
595+
it("only triggered if context is different") {
596+
let testContext = TestContext(startOnline: true)
597+
testContext.start()
598+
testContext.featureFlagCachingMock.reset()
599+
600+
testContext.subject.internalIdentify(newContext: testContext.context)
601+
testContext.subject.internalIdentify(newContext: testContext.context)
602+
testContext.subject.internalIdentify(newContext: testContext.context)
603+
testContext.subject.internalIdentify(newContext: testContext.context)
604+
605+
expect(testContext.flagStoreMock.replaceStoreCallCount) == 0
606+
expect(testContext.makeFlagSynchronizerService?.context) == testContext.context
607+
608+
expect(testContext.subject.isOnline) == true
609+
expect(testContext.subject.eventReporter.isOnline) == true
610+
expect(testContext.subject.flagSynchronizer.isOnline) == true
611+
expect(testContext.eventReporterMock.recordReceivedEvent?.kind == .identify).to(beTrue())
612+
}
595613
}
596614
}
597615

LaunchDarkly/LaunchDarklyTests/Models/Context/LDContextCodableSpec.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,17 @@ final class LDContextCodableSpec: XCTestCase {
3535

3636
func testSingleContextKindsAreDecodedAndEncodedWithoutLossOfInformation() throws {
3737
let testCases = [
38-
"{\"kind\":\"org\",\"key\":\"foo\"}",
39-
"{\"kind\":\"user\",\"key\":\"foo\"}",
40-
"{\"kind\":\"foo\",\"key\":\"bar\",\"anonymous\":true}",
41-
"{\"kind\":\"foo\",\"key\":\"bar\",\"name\":\"Foo\",\"_meta\":{\"privateAttributes\":[\"a\"]}}",
42-
"{\"kind\":\"foo\",\"key\":\"bar\",\"object\":{\"a\":\"b\"}}"
38+
"{\"key\":\"foo\",\"kind\":\"org\"}",
39+
"{\"key\":\"foo\",\"kind\":\"user\"}",
40+
"{\"anonymous\":true,\"key\":\"bar\",\"kind\":\"foo\"}",
41+
"{\"_meta\":{\"privateAttributes\":[\"a\"]},\"key\":\"bar\",\"kind\":\"foo\",\"name\":\"Foo\"}",
42+
"{\"key\":\"bar\",\"kind\":\"foo\",\"object\":{\"a\":\"b\"}}"
4343
]
4444

4545
for json in testCases {
4646
let context = try JSONDecoder().decode(LDContext.self, from: Data(json.utf8))
4747
let jsonEncoder = JSONEncoder()
48+
jsonEncoder.outputFormatting = [.sortedKeys]
4849
jsonEncoder.userInfo = [LDContext.UserInfoKeys.includePrivateAttributes:true]
4950
let output = try jsonEncoder.encode(context)
5051
let outputJson = String(data: output, encoding: .utf8)

LaunchDarkly/LaunchDarklyTests/Models/Context/LDContextSpec.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,47 @@ import XCTest
44
@testable import LaunchDarkly
55

66
final class LDContextSpec: XCTestCase {
7+
func testContextsAreEquatable() throws {
8+
var originalBuilder = LDContextBuilder(key: "context-key")
9+
originalBuilder.kind("user")
10+
originalBuilder.name("Example name")
11+
originalBuilder.trySetValue("groups", LDValue.array(["test", "it", "here"]))
12+
originalBuilder.trySetValue("address", LDValue.object(["address": "123 Easy St", "city": "Every Town"]))
13+
originalBuilder.addPrivateAttribute(Reference(literal: "name"))
14+
15+
var duplicateBuilder = LDContextBuilder(key: "context-key")
16+
duplicateBuilder.kind("user")
17+
duplicateBuilder.name("Example name")
18+
duplicateBuilder.trySetValue("groups", LDValue.array(["test", "it", "here"]))
19+
duplicateBuilder.trySetValue("address", LDValue.object(["address": "123 Easy St", "city": "Every Town"]))
20+
duplicateBuilder.addPrivateAttribute(Reference("/name"))
21+
22+
let original = try originalBuilder.build().get()
23+
let duplicate = try duplicateBuilder.build().get()
24+
25+
XCTAssertEqual(original, duplicate)
26+
}
27+
28+
func testContextsAreNotTheSame() throws {
29+
let values: [String: LDValue] = [
30+
"kind": "org",
31+
"name": "Example name",
32+
"groups": "This is a string",
33+
"address": LDValue.array(["wrong type again"])
34+
]
35+
36+
for (name, value) in values {
37+
var originalBuilder = LDContextBuilder(key: "context-key")
38+
var slightlyDifferent = LDContextBuilder(key: "context-key")
39+
slightlyDifferent.trySetValue(name, value)
40+
41+
let original = try originalBuilder.build().get()
42+
let duplicate = try slightlyDifferent.build().get()
43+
44+
XCTAssertNotEqual(original, duplicate)
45+
}
46+
}
47+
748
func testBuildCanCreateSimpleContext() throws {
849
var builder = LDContextBuilder(key: "context-key")
950
builder.name("Name")

LaunchDarkly/LaunchDarklyTests/Models/Context/ReferenceSpec.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@ import XCTest
44
@testable import LaunchDarkly
55

66
final class ReferenceSpec: XCTestCase {
7+
func testVerifyEquality() {
8+
let tests: [(Reference, Reference, Bool)] = [
9+
(Reference("name"), Reference("name"), true),
10+
(Reference("name"), Reference("/name"), true),
11+
(Reference("/first/name"), Reference("/first/name"), true),
12+
(Reference(literal: "/name"), Reference(literal: "/name"), true),
13+
(Reference(literal: "/name"), Reference("/~1name"), true),
14+
(Reference(literal: "~name"), Reference("/~0name"), true),
15+
16+
(Reference("different"), Reference("values"), false),
17+
(Reference("name/"), Reference("/name"), false),
18+
(Reference("/first/name"), Reference("/first//name"), false)
19+
]
20+
21+
for (lhs, rhs, expected) in tests {
22+
XCTAssertEqual(lhs == rhs, expected)
23+
}
24+
}
725
func testFailsWithCorrectError() {
826
let tests: [(String, ReferenceError)] = [
927
("", .empty),

0 commit comments

Comments
 (0)