Skip to content

Commit

Permalink
Release 5.4.4 (#260)
Browse files Browse the repository at this point in the history
## [5.4.4] - 2022-01-19
### Fixed
- Fixed memory leak when stream connections are terminated by updating `LDSwiftEventSource` dependency to [1.3.0](https://github.com/launchdarkly/swift-eventsource/releases/tag/1.3.0).
- The SDK would not allow additional fields on `delete` flag stream events. This has been updated to allow additional fields for improved future compatibility.
- Improved internal `Throttler` implementation to reduce concurrency concerns.
- Removed unneeded `Cartfile` definining `LDSwiftEventSource` dependency, which when bundled could lead to warning messages that `LDSwiftEventSource` definitions are implemented in multiple frameworks.
  • Loading branch information
louis-launchdarkly authored Jan 19, 2022
1 parent 7e24a7a commit a6d94a9
Show file tree
Hide file tree
Showing 22 changed files with 209 additions and 336 deletions.
46 changes: 30 additions & 16 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
type: string
ssh-fix:
type: boolean
default: true
default: false
build-doc:
type: boolean
default: false
Expand All @@ -24,19 +24,15 @@ jobs:
steps:
- checkout

# This hack shouldn't be necessary, as we don't actually use SSH
# to get any dependencies, but for some reason starting in the
# '12.0.0' Xcode image it's become necessary.
# There's an XCode bug present in the 12.0.1 CircleCI image that prevents fetching SSH
# dependencies from working in some cases, so we disable CircleCI's rewriting of the HTTPS
# GitHub URLs to SSH.
- when:
condition: <<parameters.ssh-fix>>
steps:
- run:
name: SSH fingerprint fix
command: |
sudo defaults write com.apple.dt.Xcode IDEPackageSupportUseBuiltinSCM YES
rm ~/.ssh/id_rsa || true
for ip in $(dig @8.8.8.8 bitbucket.org +short); do ssh-keyscan bitbucket.org,$ip; ssh-keyscan $ip; done 2>/dev/null >> ~/.ssh/known_hosts || true
for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan github.com,$ip; ssh-keyscan $ip; done 2>/dev/null >> ~/.ssh/known_hosts || true
name: SSH fix
command: git config --global --unset url.ssh://[email protected]

- run:
name: Setup for builds
Expand Down Expand Up @@ -87,11 +83,25 @@ jobs:
- when:
condition: <<parameters.build-doc>>
steps:
- restore_cache:
key: v1-gem-cache-<<parameters.xcode-version>>-

- run:
name: Build Documentation
name: Install jazzy gem
command: |
sudo gem install jazzy
jazzy -o artifacts/docs
gem install jazzy
gem cleanup
# Used as cache key to prevent storing redundant caches
gem list > /tmp/cache-key.txt
- save_cache:
key: v1-gem-cache-<<parameters.xcode-version>>-{{ checksum "/tmp/cache-key.txt" }}
paths:
- ~/.gem

- run:
name: Build Documentation
command: jazzy -o artifacts/docs

- when:
condition: <<parameters.run-lint>>
Expand All @@ -116,18 +126,22 @@ workflows:

build:
jobs:
- build:
name: Xcode 13.1 - Swift 5.5
xcode-version: '13.1.0'
ios-sim: 'platform=iOS Simulator,name=iPhone 11,OS=15.0'
build-doc: true
run-lint: true
- build:
name: Xcode 12.5 - Swift 5.4
xcode-version: '12.5.0'
ios-sim: 'platform=iOS Simulator,name=iPhone 8,OS=14.5'
build-doc: true
run-lint: true
- build:
name: Xcode 12.0 - Swift 5.3
xcode-version: '12.0.1'
ios-sim: 'platform=iOS Simulator,name=iPhone 8,OS=14.0'
ssh-fix: true
- build:
name: Xcode 11.4 - Swift 5.2
xcode-version: '11.4.1'
ios-sim: 'platform=iOS Simulator,name=iPhone 8,OS=12.2'
ssh-fix: false
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

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.4] - 2022-01-19
### Fixed
- Fixed memory leak when stream connections are terminated by updating `LDSwiftEventSource` dependency to [1.3.0](https://github.com/launchdarkly/swift-eventsource/releases/tag/1.3.0).
- The SDK would not allow additional fields on `delete` flag stream events. This has been updated to allow additional fields for improved future compatibility.
- Improved internal `Throttler` implementation to reduce concurrency concerns.
- Removed unneeded `Cartfile` definining `LDSwiftEventSource` dependency, which when bundled could lead to warning messages that `LDSwiftEventSource` definitions are implemented in multiple frameworks.

## [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.
Expand Down
1 change: 0 additions & 1 deletion Cartfile

This file was deleted.

4 changes: 2 additions & 2 deletions 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.3"
ld.version = "5.4.4"
ld.summary = "iOS SDK for LaunchDarkly"

ld.description = <<-DESC
Expand Down Expand Up @@ -35,6 +35,6 @@ Pod::Spec.new do |ld|
ld.swift_version = '5.0'

ld.subspec 'Core' do |es|
es.dependency 'LDSwiftEventSource', '1.2.1'
es.dependency 'LDSwiftEventSource', '1.3.0'
end
end
26 changes: 13 additions & 13 deletions LaunchDarkly.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1583,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.3;
MARKETING_VERSION = 5.4.4;
MODULEMAP_FILE = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
PRODUCT_NAME = LaunchDarkly_tvOS;
Expand All @@ -1606,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.3;
MARKETING_VERSION = 5.4.4;
MODULEMAP_FILE = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
PRODUCT_NAME = LaunchDarkly_tvOS;
Expand All @@ -1629,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.3;
MARKETING_VERSION = 5.4.4;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
PRODUCT_NAME = LaunchDarkly_macOS;
SDKROOT = macosx;
Expand All @@ -1650,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.3;
MARKETING_VERSION = 5.4.4;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
PRODUCT_NAME = LaunchDarkly_macOS;
SDKROOT = macosx;
Expand Down Expand Up @@ -1694,7 +1694,7 @@
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 5.4.0;
DYLIB_CURRENT_VERSION = 5.4.3;
DYLIB_CURRENT_VERSION = 5.4.4;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_VERSION = B;
Expand Down Expand Up @@ -1765,7 +1765,7 @@
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 5.4.0;
DYLIB_CURRENT_VERSION = 5.4.3;
DYLIB_CURRENT_VERSION = 5.4.4;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = B;
Expand Down Expand Up @@ -1804,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.3;
MARKETING_VERSION = 5.4.4;
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
PRODUCT_NAME = LaunchDarkly;
Expand All @@ -1824,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.3;
MARKETING_VERSION = 5.4.4;
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
PRODUCT_NAME = LaunchDarkly;
Expand Down Expand Up @@ -1866,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.3;
MARKETING_VERSION = 5.4.4;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
PRODUCT_NAME = LaunchDarkly_watchOS;
SDKROOT = watchos;
Expand All @@ -1888,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.3;
MARKETING_VERSION = 5.4.4;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
PRODUCT_NAME = LaunchDarkly_watchOS;
SDKROOT = watchos;
Expand Down Expand Up @@ -1962,7 +1962,7 @@
repositoryURL = "https://github.com/LaunchDarkly/swift-eventsource.git";
requirement = {
kind = exactVersion;
version = 1.2.1;
version = 1.3.0;
};
};
B4903D9624BD61B200F087C4 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */ = {
Expand All @@ -1978,15 +1978,15 @@
repositoryURL = "https://github.com/Quick/Nimble.git";
requirement = {
kind = exactVersion;
version = 9.2.0;
version = 9.2.1;
};
};
B4903D9C24BD61EF00F087C4 /* XCRemoteSwiftPackageReference "Quick" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Quick/Quick.git";
requirement = {
kind = exactVersion;
version = 3.1.2;
version = 4.0.0;
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down
2 changes: 1 addition & 1 deletion LaunchDarkly/LaunchDarkly/Models/ErrorObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation

struct ErrorObserver {
weak var owner: LDObserverOwner?
var errorHandler: LDErrorHandler?
let errorHandler: LDErrorHandler

init(owner: LDObserverOwner, errorHandler: @escaping LDErrorHandler) {
self.owner = owner
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class DiagnosticReporter: DiagnosticReporting {
sendDiagnosticEventAsync(diagnosticEvent: initEvent)
}

timer = LDTimer(withTimeInterval: service.config.diagnosticRecordingInterval, repeats: true, fireQueue: workQueue) {
timer = LDTimer(withTimeInterval: service.config.diagnosticRecordingInterval, fireQueue: workQueue) {
self.sendDiagnosticEventSync(diagnosticEvent: cache.getCurrentStatsAndReset())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ struct EnvironmentReporter: EnvironmentReporting {
var shouldThrottleOnlineCalls: Bool { true }
#endif

let sdkVersion = "5.4.3"
let sdkVersion = "5.4.4"
// Unfortunately, the following does not function in certain configurations, such as when included through SPM
// var sdkVersion: String {
// Bundle(for: LDClient.self).infoDictionary?["CFBundleShortVersionString"] as? String ?? "5.x"
Expand Down
16 changes: 2 additions & 14 deletions LaunchDarkly/LaunchDarkly/ServiceObjects/ErrorNotifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,15 @@ final class ErrorNotifier: ErrorNotifying {
}

func removeObservers(for owner: LDObserverOwner) {
errorObservers = errorObservers.filter { $0.owner !== owner }
errorObservers.removeAll { $0.owner === owner }
}

func notifyObservers(of error: Error) {
removeOldObservers()
errorObservers.forEach { $0.errorHandler?(error) }
errorObservers.forEach { $0.errorHandler(error) }
}

private func removeOldObservers() {
errorObservers = errorObservers.filter { $0.owner != nil }
}
}

#if DEBUG
extension ErrorNotifier {
func erase(owner: LDObserverOwner) {
for index in 0..<errorObservers.count {
guard errorObservers[index].owner === owner
else { continue }
errorObservers[index].owner = nil
}
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class EventReporter: EventReporting {
private func startReporting(isOnline: Bool) {
guard isOnline && !isReportingActive
else { return }
eventReportTimer = LDTimer(withTimeInterval: service.config.eventFlushInterval, repeats: true, fireQueue: eventQueue, execute: reportEvents)
eventReportTimer = LDTimer(withTimeInterval: service.config.eventFlushInterval, fireQueue: eventQueue, execute: reportEvents)
}

private func stopReporting() {
Expand Down
3 changes: 1 addition & 2 deletions LaunchDarkly/LaunchDarkly/ServiceObjects/FlagStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ final class FlagStore: FlagMaintaining {
}
}
}
guard deleteDictionary.keys.sorted() == [Keys.flagKey, FeatureFlag.CodingKeys.version.rawValue],
let flagKey = deleteDictionary[Keys.flagKey] as? String,
guard let flagKey = deleteDictionary[Keys.flagKey] as? String,
let newVersion = deleteDictionary[FeatureFlag.CodingKeys.version.rawValue] as? Int
else {
Log.debug(self.typeName(and: #function) + "aborted. Malformed delete dictionary. deleteDictionary: \(String(describing: deleteDictionary))")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ class FlagSynchronizer: LDFlagSynchronizing, EventHandler {
return
}
Log.debug(typeName(and: #function))
flagRequestTimer = LDTimer(withTimeInterval: pollingInterval, repeats: true, fireQueue: syncQueue, execute: processTimer)
flagRequestTimer = LDTimer(withTimeInterval: pollingInterval, fireQueue: syncQueue, execute: processTimer)
makeFlagRequest(isOnline: isOnline)
}

Expand Down
22 changes: 3 additions & 19 deletions LaunchDarkly/LaunchDarkly/ServiceObjects/LDTimer.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
//
// LDTimer.swift
// LaunchDarkly
//
// Copyright © 2019 Catamorphic Co. All rights reserved.
//

import Foundation

protocol TimeResponding {
var isRepeating: Bool { get }
var fireDate: Date? { get }

init(withTimeInterval: TimeInterval, repeats: Bool, fireQueue: DispatchQueue, execute: @escaping () -> Void)
init(withTimeInterval: TimeInterval, fireQueue: DispatchQueue, execute: @escaping () -> Void)
func cancel()
}

Expand All @@ -20,17 +12,15 @@ final class LDTimer: TimeResponding {
private (set) weak var timer: Timer?
private let fireQueue: DispatchQueue
private let execute: () -> Void
private (set) var isRepeating: Bool
private (set) var isCancelled: Bool = false
var fireDate: Date? { timer?.fireDate }

init(withTimeInterval timeInterval: TimeInterval, repeats: Bool, fireQueue: DispatchQueue = DispatchQueue.main, execute: @escaping () -> Void) {
isRepeating = repeats
init(withTimeInterval timeInterval: TimeInterval, fireQueue: DispatchQueue = DispatchQueue.main, execute: @escaping () -> Void) {
self.fireQueue = fireQueue
self.execute = execute

// the run loop retains the timer, so the property is weak to avoid a retain cycle. Setting the timer to a strong reference is important so that the timer doesn't get nil'd before it's added to the run loop.
let timer = Timer(timeInterval: timeInterval, target: self, selector: #selector(timerFired), userInfo: nil, repeats: repeats)
let timer = Timer(timeInterval: timeInterval, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
self.timer = timer
RunLoop.main.add(timer, forMode: RunLoop.Mode.default)
}
Expand All @@ -52,9 +42,3 @@ final class LDTimer: TimeResponding {
isCancelled = true
}
}

#if DEBUG
extension LDTimer {
var testFireQueue: DispatchQueue { fireQueue }
}
#endif
Loading

0 comments on commit a6d94a9

Please sign in to comment.