Skip to content

Commit

Permalink
Prepare 5.4.3 release (#254)
Browse files Browse the repository at this point in the history
## [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.
  • Loading branch information
gwhelanLD authored Aug 13, 2021
1 parent 981f571 commit 7e24a7a
Show file tree
Hide file tree
Showing 68 changed files with 1,127 additions and 2,045 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

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

## [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.

## [5.4.2] - 2021-06-17
### Fixed
- 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)!)
Expand Down
2 changes: 1 addition & 1 deletion LaunchDarkly.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Pod::Spec.new do |ld|

ld.name = "LaunchDarkly"
ld.version = "5.4.2"
ld.version = "5.4.3"
ld.summary = "iOS SDK for LaunchDarkly"

ld.description = <<-DESC
Expand Down
42 changes: 15 additions & 27 deletions LaunchDarkly.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

/* Begin PBXBuildFile section */
830BF933202D188E006DF9B1 /* HTTPURLRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830BF932202D188E006DF9B1 /* HTTPURLRequest.swift */; };
830DB3AA223409D800D65D25 /* URLCacheSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830DB3A9223409D800D65D25 /* URLCacheSpec.swift */; };
830DB3AC22380A3E00D65D25 /* HTTPHeadersSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830DB3AB22380A3E00D65D25 /* HTTPHeadersSpec.swift */; };
830DB3AE2239B54900D65D25 /* URLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830DB3AD2239B54900D65D25 /* URLResponse.swift */; };
830DB3AF2239B54900D65D25 /* URLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830DB3AD2239B54900D65D25 /* URLResponse.swift */; };
Expand Down Expand Up @@ -373,7 +372,6 @@

/* Begin PBXFileReference section */
830BF932202D188E006DF9B1 /* HTTPURLRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPURLRequest.swift; sourceTree = "<group>"; };
830DB3A9223409D800D65D25 /* URLCacheSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLCacheSpec.swift; sourceTree = "<group>"; };
830DB3AB22380A3E00D65D25 /* HTTPHeadersSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPHeadersSpec.swift; sourceTree = "<group>"; };
830DB3AD2239B54900D65D25 /* URLResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLResponse.swift; sourceTree = "<group>"; };
831188382113A16900D77CB5 /* LaunchDarkly_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LaunchDarkly_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -583,7 +581,6 @@
83396BC81F7C3711000E256E /* DarklyServiceSpec.swift */,
832307A51F7D8D720029815A /* URLRequestSpec.swift */,
8392FFA22033565700320914 /* HTTPURLResponse.swift */,
830DB3A9223409D800D65D25 /* URLCacheSpec.swift */,
830DB3AB22380A3E00D65D25 /* HTTPHeadersSpec.swift */,
);
path = Networking;
Expand Down Expand Up @@ -708,14 +705,14 @@
8354EFE61F263E4200C05156 /* Models */ = {
isa = PBXGroup;
children = (
8354EFDD1F26380700C05156 /* LDConfig.swift */,
83EBCB9E20D9A120003A7142 /* User */,
83EBCB9D20D9A0A1003A7142 /* FeatureFlag */,
8354EFDE1F26380700C05156 /* Event.swift */,
83883DD4220B68A000EEAB95 /* ErrorObserver.swift */,
8354AC5F224150C300CDE602 /* Cache */,
C408884823033B7500420721 /* ConnectionInformation.swift */,
B4C9D42D2489B5FF004A9B03 /* DiagnosticEvent.swift */,
83883DD4220B68A000EEAB95 /* ErrorObserver.swift */,
8354EFDE1F26380700C05156 /* Event.swift */,
83EBCB9D20D9A0A1003A7142 /* FeatureFlag */,
8354EFDD1F26380700C05156 /* LDConfig.swift */,
83A2D6231F51CD7A00EA3BD4 /* LDUser.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -792,14 +789,6 @@
path = FeatureFlag;
sourceTree = "<group>";
};
83EBCB9E20D9A120003A7142 /* User */ = {
isa = PBXGroup;
children = (
83A2D6231F51CD7A00EA3BD4 /* LDUser.swift */,
);
path = User;
sourceTree = "<group>";
};
83EBCB9F20D9A143003A7142 /* FlagChange */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1474,7 +1463,6 @@
8335299E1FC37727001166F8 /* FlagMaintainingMock.swift in Sources */,
83383A5120460DD30024D975 /* SynchronizingErrorSpec.swift in Sources */,
8354AC6E22418C1F00CDE602 /* CacheableUserEnvironmentFlagsSpec.swift in Sources */,
830DB3AA223409D800D65D25 /* URLCacheSpec.swift in Sources */,
83B9A080204F56F4000C3F17 /* FlagChangeObserverSpec.swift in Sources */,
830DB3AC22380A3E00D65D25 /* HTTPHeadersSpec.swift in Sources */,
83D15235225299890054B6D4 /* DeprecatedCacheModelV2Spec.swift in Sources */,
Expand Down Expand Up @@ -1595,7 +1583,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
MODULEMAP_FILE = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
PRODUCT_NAME = LaunchDarkly_tvOS;
Expand All @@ -1618,7 +1606,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
MODULEMAP_FILE = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
PRODUCT_NAME = LaunchDarkly_tvOS;
Expand All @@ -1641,7 +1629,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
PRODUCT_NAME = LaunchDarkly_macOS;
SDKROOT = macosx;
Expand All @@ -1662,7 +1650,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
PRODUCT_NAME = LaunchDarkly_macOS;
SDKROOT = macosx;
Expand Down Expand Up @@ -1706,7 +1694,7 @@
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 5.4.0;
DYLIB_CURRENT_VERSION = 5.4.2;
DYLIB_CURRENT_VERSION = 5.4.3;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_VERSION = B;
Expand Down Expand Up @@ -1777,7 +1765,7 @@
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 5.4.0;
DYLIB_CURRENT_VERSION = 5.4.2;
DYLIB_CURRENT_VERSION = 5.4.3;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = B;
Expand Down Expand Up @@ -1816,7 +1804,7 @@
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
PRODUCT_NAME = LaunchDarkly;
Expand All @@ -1836,7 +1824,7 @@
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
PRODUCT_NAME = LaunchDarkly;
Expand Down Expand Up @@ -1878,7 +1866,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
PRODUCT_NAME = LaunchDarkly_watchOS;
SDKROOT = watchos;
Expand All @@ -1900,7 +1888,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
PRODUCT_NAME = LaunchDarkly_watchOS;
SDKROOT = watchos;
Expand Down
16 changes: 11 additions & 5 deletions LaunchDarkly/GeneratedCode/mocks.generated.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Generated using Sourcery 0.16.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 1.2.1 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT


import Foundation
import LDSwiftEventSource
@testable import LaunchDarkly
Expand Down Expand Up @@ -372,12 +371,19 @@ final class FlagChangeNotifyingMock: FlagChangeNotifying {
notifyConnectionModeChangedObserversCallback?()
}

var notifyUnchangedCallCount = 0
var notifyUnchangedCallback: (() -> Void)?
func notifyUnchanged() {
notifyUnchangedCallCount += 1
notifyUnchangedCallback?()
}

var notifyObserversCallCount = 0
var notifyObserversCallback: (() -> Void)?
var notifyObserversReceivedArguments: (flagStore: FlagMaintaining, oldFlags: [LDFlagKey: FeatureFlag])?
func notifyObservers(flagStore: FlagMaintaining, oldFlags: [LDFlagKey: FeatureFlag]) {
var notifyObserversReceivedArguments: (oldFlags: [LDFlagKey: FeatureFlag], newFlags: [LDFlagKey: FeatureFlag])?
func notifyObservers(oldFlags: [LDFlagKey: FeatureFlag], newFlags: [LDFlagKey: FeatureFlag]) {
notifyObserversCallCount += 1
notifyObserversReceivedArguments = (flagStore: flagStore, oldFlags: oldFlags)
notifyObserversReceivedArguments = (oldFlags: oldFlags, newFlags: newFlags)
notifyObserversCallback?()
}
}
Expand Down
4 changes: 2 additions & 2 deletions LaunchDarkly/LaunchDarkly/Extensions/AnyComparer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import Foundation
struct AnyComparer {
private init() { }

//If editing this method to add classes here, update AnySpec with tests that verify the comparison for that class
//swiftlint:disable:next cyclomatic_complexity
// If editing this method to add classes here, update AnySpec with tests that verify the comparison for that class
// swiftlint:disable:next cyclomatic_complexity
static func isEqual(_ value: Any, to other: Any) -> Bool {
switch (value, other) {
case let (value, other) as (Bool, Bool):
Expand Down
2 changes: 1 addition & 1 deletion LaunchDarkly/LaunchDarkly/Extensions/DateFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extension DateFormatter {
let httpUrlHeaderFormatter = DateFormatter()
httpUrlHeaderFormatter.locale = Locale(identifier: "en_US_POSIX")
httpUrlHeaderFormatter.timeZone = TimeZone(abbreviation: "GMT")
httpUrlHeaderFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz" //Mon, 07 May 2018 19:46:29 GMT
httpUrlHeaderFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz" // Mon, 07 May 2018 19:46:29 GMT

return httpUrlHeaderFormatter
}
Expand Down
25 changes: 24 additions & 1 deletion LaunchDarkly/LaunchDarkly/Extensions/Dictionary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,33 @@ extension Dictionary where Key == String {

extension Dictionary where Key == String, Value == Any {
var withNullValuesRemoved: [String: Any] {
self.filter { !($1 is NSNull) }.mapValues { value in
(self as [String: Any?]).compactMapValues { value in
if value is NSNull {
return nil
}
if let dictionary = value as? [String: Any] {
return dictionary.withNullValuesRemoved
}
if let arr = value as? [Any] {
return arr.withNullValuesRemoved
}
return value
}
}
}

private extension Array where Element == Any {
var withNullValuesRemoved: [Any] {
(self as [Any?]).compactMap { value in
if value is NSNull {
return nil
}
if let arr = value as? [Any] {
return arr.withNullValuesRemoved
}
if let dict = value as? [String: Any] {
return dict.withNullValuesRemoved
}
return value
}
}
Expand Down
21 changes: 10 additions & 11 deletions LaunchDarkly/LaunchDarkly/LDClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ public class LDClient {
internalSetOnlineQueue.sync {
guard goOnline, self.canGoOnline
else {
//go offline, which is not throttled
// go offline, which is not throttled
self.go(online: false, reasonOnlineUnavailable: self.reasonOnlineUnavailable(goOnline: goOnline), completion: completion)
return
}

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

let config: LDConfig
let service: DarklyServiceProvider
private(set) var user: LDUser

/**
Expand Down Expand Up @@ -310,6 +311,7 @@ public class LDClient {
flagStore.replaceStore(newFlags: user.flagStore?.featureFlags ?? [:], completion: nil)
}
self.service.user = self.user
self.service.clearFlagResponseCache()
flagSynchronizer = serviceFactory.makeFlagSynchronizer(streamingMode: ConnectionInformation.effectiveStreamingMode(config: config, ldClient: self),
pollingInterval: config.flagPollingInterval(runMode: runMode),
useReport: config.useReport,
Expand All @@ -325,15 +327,11 @@ public class LDClient {
if !config.autoAliasingOptOut && previousUser.isAnonymous && !newUser.isAnonymous {
self.alias(context: newUser, previousContext: previousUser)
}

self.service.clearFlagResponseCache()
}
}

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

let service: DarklyServiceProvider

// MARK: Retrieving Flag Values

/**
Expand Down Expand Up @@ -375,7 +373,7 @@ public class LDClient {
*/
/// - Tag: variationWithdefaultValue
public func variation<T: LDFlagValueConvertible>(forKey flagKey: LDFlagKey, defaultValue: T) -> T {
//the defaultValue cast to 'as T?' directs the call to the Optional-returning variation method
// the defaultValue cast to 'as T?' directs the call to the Optional-returning variation method
variation(forKey: flagKey, defaultValue: defaultValue as T?) ?? defaultValue
}

Expand Down Expand Up @@ -694,6 +692,9 @@ public class LDClient {
self.updateCacheAndReportChanges(user: self.user, oldFlags: oldFlags)
}
}
case .upToDate:
connectionInformation.lastKnownFlagValidity = Date()
flagChangeNotifier.notifyUnchanged()
case .error(let synchronizingError):
process(synchronizingError, logPrefix: typeName(and: #function, appending: ": "))
}
Expand All @@ -713,7 +714,7 @@ public class LDClient {
private func updateCacheAndReportChanges(user: LDUser,
oldFlags: [LDFlagKey: FeatureFlag]) {
flagCache.storeFeatureFlags(flagStore.featureFlags, userKey: user.key, mobileKey: config.mobileKey, lastUpdated: Date(), storeMode: .async)
flagChangeNotifier.notifyObservers(flagStore: flagStore, oldFlags: oldFlags)
flagChangeNotifier.notifyObservers(oldFlags: oldFlags, newFlags: flagStore.featureFlags)
}

// MARK: Events
Expand Down Expand Up @@ -790,7 +791,7 @@ public class LDClient {
Log.debug(typeName(and: #function) + "result: \(result)")
switch result {
case .success:
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.
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.
case .error(let synchronizingError):
process(synchronizingError, logPrefix: typeName(and: #function, appending: ": "))
}
Expand Down Expand Up @@ -828,8 +829,6 @@ public class LDClient {
return
}

HTTPHeaders.removeFlagRequestEtags()

let internalUser = user

LDClient.instances = [:]
Expand Down
14 changes: 7 additions & 7 deletions LaunchDarkly/LaunchDarkly/LDCommon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@

import Foundation

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

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

extension LDFlagKey {
Expand Down
Loading

0 comments on commit 7e24a7a

Please sign in to comment.