diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6d296b25a..042a1d6a2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,9 @@
## Changelog
+- **3.1.4**:
+ - Bugfix: Possible crash fixed when IVI was 1 and IV Index 0 (#358).
+ - Bugfix: Multiple `self` weakened (#356).
+ - Allowing groups to be null when importing (#348, #357).
+
- **3.1.3**:
- Improvement: Migration to Xcode 12.5.
* Improvement: CryptoSwift updated from 1.3.8 to 1.4.0 (https://github.com/krzyzanowskim/CryptoSwift/releases/tag/1.4.0).
diff --git a/Documentation/SETTING_UP.md b/Documentation/SETTING_UP.md
index 1929aa75f..b0b22fd6a 100644
--- a/Documentation/SETTING_UP.md
+++ b/Documentation/SETTING_UP.md
@@ -7,7 +7,7 @@ Using CocoaPods:
You can use [Swift Package Manager](https://swift.org/package-manager/) and specify dependency in `Package.swift` by adding this:
```swift
-.package(url: "https://github.com/NordicSemiconductor/IOS-nRF-Mesh-Library", .upToNextMinor(from: "3.1.2"))
+.package(url: "https://github.com/NordicSemiconductor/IOS-nRF-Mesh-Library", .upToNextMinor(from: "3.1.4"))
```
Also, have a look at [Swift Package Manager @ CryptoSwift](https://github.com/krzyzanowskim/CryptoSwift/blob/master/README.md#swift-package-manager).
diff --git a/Example/Podfile.lock b/Example/Podfile.lock
index 30f0683d0..df93714f3 100755
--- a/Example/Podfile.lock
+++ b/Example/Podfile.lock
@@ -1,6 +1,6 @@
PODS:
- CryptoSwift (1.4.0)
- - nRFMeshProvision (3.1.3):
+ - nRFMeshProvision (3.1.4):
- CryptoSwift (= 1.4.0)
DEPENDENCIES:
@@ -16,7 +16,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
CryptoSwift: 7cc902df1784de3b389a387756c7d710f197730c
- nRFMeshProvision: 7c95bc28df2ee8ba97ce1df73d04714b5abca1ca
+ nRFMeshProvision: 4b3e185fd13b077c997aadca6f54806f5c577cd7
PODFILE CHECKSUM: 69a81463322ef34ca0a20b98e90da2701d94e4ec
diff --git a/Example/Pods/Local Podspecs/nRFMeshProvision.podspec.json b/Example/Pods/Local Podspecs/nRFMeshProvision.podspec.json
index cdacc02f7..08a14c105 100755
--- a/Example/Pods/Local Podspecs/nRFMeshProvision.podspec.json
+++ b/Example/Pods/Local Podspecs/nRFMeshProvision.podspec.json
@@ -1,6 +1,6 @@
{
"name": "nRFMeshProvision",
- "version": "3.1.3",
+ "version": "3.1.4",
"summary": "A Bluetooth Mesh library",
"description": "nRF Mesh is a Bluetooth Mesh compliant library that has many features such as provisioning, configuration and control of Bluetooth Mesh compliant nodes.",
"homepage": "https://github.com/NordicSemiconductor/IOS-nRF-Mesh-Library",
@@ -13,7 +13,7 @@
},
"source": {
"git": "https://github.com/NordicSemiconductor/IOS-nRF-Mesh-Library.git",
- "tag": "3.1.3"
+ "tag": "3.1.4"
},
"social_media_url": "https://twitter.com/nordictweets",
"platforms": {
diff --git a/Example/Pods/Manifest.lock b/Example/Pods/Manifest.lock
index 30f0683d0..df93714f3 100755
--- a/Example/Pods/Manifest.lock
+++ b/Example/Pods/Manifest.lock
@@ -1,6 +1,6 @@
PODS:
- CryptoSwift (1.4.0)
- - nRFMeshProvision (3.1.3):
+ - nRFMeshProvision (3.1.4):
- CryptoSwift (= 1.4.0)
DEPENDENCIES:
@@ -16,7 +16,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
CryptoSwift: 7cc902df1784de3b389a387756c7d710f197730c
- nRFMeshProvision: 7c95bc28df2ee8ba97ce1df73d04714b5abca1ca
+ nRFMeshProvision: 4b3e185fd13b077c997aadca6f54806f5c577cd7
PODFILE CHECKSUM: 69a81463322ef34ca0a20b98e90da2701d94e4ec
diff --git a/Example/Pods/Target Support Files/nRFMeshProvision/nRFMeshProvision-Info.plist b/Example/Pods/Target Support Files/nRFMeshProvision/nRFMeshProvision-Info.plist
index 8b511bb39..36f2c7e22 100644
--- a/Example/Pods/Target Support Files/nRFMeshProvision/nRFMeshProvision-Info.plist
+++ b/Example/Pods/Target Support Files/nRFMeshProvision/nRFMeshProvision-Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 3.1.3
+ 3.1.4
CFBundleSignature
????
CFBundleVersion
diff --git a/Example/nRFMeshProvision/Utils/UIViewController+Alert.swift b/Example/nRFMeshProvision/Utils/UIViewController+Alert.swift
index 692f5afd5..4fe0a644d 100644
--- a/Example/nRFMeshProvision/Utils/UIViewController+Alert.swift
+++ b/Example/nRFMeshProvision/Utils/UIViewController+Alert.swift
@@ -63,7 +63,8 @@ extension UIViewController {
// TODO: Should only iPad be handled differently? How about carPlay or Apple TV?
let ipad = UIDevice.current.userInterfaceIdiom == .pad
let style: UIAlertController.Style = ipad ? .alert : .actionSheet
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
let alert = UIAlertController(title: title, message: message, preferredStyle: style)
alert.addAction(UIAlertAction(title: "Confirm", style: .destructive, handler: handler))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
@@ -84,7 +85,8 @@ extension UIViewController {
func presentAlert(title: String?, message: String?, cancelable: Bool = false,
option action: UIAlertAction? = nil,
handler: ((UIAlertAction) -> Void)? = nil) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: cancelable ? "Cancel" : "OK", style: .cancel, handler: handler))
if let action = action {
@@ -107,7 +109,8 @@ extension UIViewController {
func presentRangeAlert(title: String?, message: String?, range: RangeObject? = nil,
type selector: Selector? = nil,
handler: ((ClosedRange) -> Void)? = nil) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
var alert: UIAlertController? = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert!.addTextField { textField in
textField.text = range?.lowerBound.hex
@@ -165,7 +168,8 @@ extension UIViewController {
func presentTextAlert(title: String?, message: String?, text: String? = "", placeHolder: String? = "",
type selector: Selector? = nil, option action: UIAlertAction? = nil,
cancelHandler: (() -> Void)? = nil, handler: ((String) -> Void)? = nil) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
var alert: UIAlertController? = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert!.addTextField { textField in
textField.text = text
@@ -219,7 +223,8 @@ extension UIViewController {
/// - handler: The OK or Generate button handler.
func presentKeyDialog(title: String?, message: String?, key: Data? = nil,
handler: ((Data) -> Void)? = nil) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
var alert: UIAlertController? = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert!.addTextField { textField in
textField.text = key?.hex ?? Data.random128BitKey().hex
diff --git a/Example/nRFMeshProvision/View Controllers/Groups/AddGroupViewController.swift b/Example/nRFMeshProvision/View Controllers/Groups/AddGroupViewController.swift
index 889bb54d0..1e68e2bb5 100644
--- a/Example/nRFMeshProvision/View Controllers/Groups/AddGroupViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Groups/AddGroupViewController.swift
@@ -147,8 +147,8 @@ private extension AddGroupViewController {
}
presentTextAlert(title: "Group address", message: "Hexadecimal value in range\nC000 - FEFF.",
text: address?.hex, placeHolder: "Address", type: .groupAddressRequired,
- option: action, cancelHandler: nil) { text in
- self.address = MeshAddress(hex: text)
+ option: action, cancelHandler: nil) { [weak self] text in
+ self?.address = MeshAddress(hex: text)
}
}
diff --git a/Example/nRFMeshProvision/View Controllers/Groups/Model/SceneServerGroupCell.swift b/Example/nRFMeshProvision/View Controllers/Groups/Model/SceneServerGroupCell.swift
index 8e3bfb92f..3097c8748 100644
--- a/Example/nRFMeshProvision/View Controllers/Groups/Model/SceneServerGroupCell.swift
+++ b/Example/nRFMeshProvision/View Controllers/Groups/Model/SceneServerGroupCell.swift
@@ -80,8 +80,8 @@ private extension SceneServerGroupCell {
}
let alert = UIAlertController(title: "Select scene", message: nil, preferredStyle: .actionSheet)
scenes.forEach { scene in
- alert.addAction(UIAlertAction(title: scene.name, style: .default) { _ in
- self.sendSceneRecall(scene.number)
+ alert.addAction(UIAlertAction(title: scene.name, style: .default) { [weak self] _ in
+ self?.sendSceneRecall(scene.number)
})
}
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
diff --git a/Example/nRFMeshProvision/View Controllers/Groups/Model/SceneSetupServerGroupCell.swift b/Example/nRFMeshProvision/View Controllers/Groups/Model/SceneSetupServerGroupCell.swift
index ae23d2dd5..06f150787 100644
--- a/Example/nRFMeshProvision/View Controllers/Groups/Model/SceneSetupServerGroupCell.swift
+++ b/Example/nRFMeshProvision/View Controllers/Groups/Model/SceneSetupServerGroupCell.swift
@@ -78,8 +78,8 @@ private extension SceneSetupServerGroupCell {
}
let alert = UIAlertController(title: "Select scene", message: nil, preferredStyle: .actionSheet)
network.scenes.forEach { scene in
- alert.addAction(UIAlertAction(title: scene.name, style: .default) { _ in
- self.sendSceneStore(scene.number)
+ alert.addAction(UIAlertAction(title: scene.name, style: .default) { [weak self] _ in
+ self?.sendSceneStore(scene.number)
})
}
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
diff --git a/Example/nRFMeshProvision/View Controllers/Network/Configuration/ConfigurationViewController.swift b/Example/nRFMeshProvision/View Controllers/Network/Configuration/ConfigurationViewController.swift
index 58a356664..4ff815425 100644
--- a/Example/nRFMeshProvision/View Controllers/Network/Configuration/ConfigurationViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Network/Configuration/ConfigurationViewController.swift
@@ -375,7 +375,7 @@ private extension ConfigurationViewController {
let alert = UIAlertController(title: "Reset Node",
message: "Resetting the node will change its state back to unprovisioned state and remove it from the local database.",
preferredStyle: .actionSheet)
- let resetAction = UIAlertAction(title: "Reset", style: .destructive) { _ in self.resetNode() }
+ let resetAction = UIAlertAction(title: "Reset", style: .destructive) { [weak self] _ in self?.resetNode() }
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
alert.addAction(resetAction)
alert.addAction(cancelAction)
@@ -390,7 +390,7 @@ private extension ConfigurationViewController {
let alert = UIAlertController(title: "Remove Node",
message: "The node will only be removed from the local database. It will still be able to send and receive messages from the network. Remove the node only if the device is no longer available.",
preferredStyle: .actionSheet)
- let resetAction = UIAlertAction(title: "Remove", style: .destructive) { _ in self.removeNode() }
+ let resetAction = UIAlertAction(title: "Remove", style: .destructive) { [weak self] _ in self?.removeNode() }
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
alert.addAction(resetAction)
alert.addAction(cancelAction)
diff --git a/Example/nRFMeshProvision/View Controllers/Network/Configuration/NodeScenesViewController.swift b/Example/nRFMeshProvision/View Controllers/Network/Configuration/NodeScenesViewController.swift
index 379fdf2c1..e306f96f7 100644
--- a/Example/nRFMeshProvision/View Controllers/Network/Configuration/NodeScenesViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Network/Configuration/NodeScenesViewController.swift
@@ -367,8 +367,8 @@ private extension NodeScenesViewController {
return false
}
guard isSceneClientReady else {
- let action = UIAlertAction(title: "Fix", style: .default) { [unowned self] action in
- self.fixClient()
+ let action = UIAlertAction(title: "Fix", style: .default) { [weak self] action in
+ self?.fixClient()
}
presentAlert(title: "Client not ready",
message: "Scene Client model on local node is not bound to any of the "
@@ -390,8 +390,8 @@ private extension NodeScenesViewController {
return false
}
guard isSceneClientReadyToSetup else {
- let action = UIAlertAction(title: "Fix", style: .default) { [unowned self] action in
- self.fixClient()
+ let action = UIAlertAction(title: "Fix", style: .default) { [weak self] action in
+ self?.fixClient()
}
presentAlert(title: "Client not ready",
message: "Scene Client model on local node is not bound to any of the "
diff --git a/Example/nRFMeshProvision/View Controllers/Network/Configuration/SetPublicationViewController.swift b/Example/nRFMeshProvision/View Controllers/Network/Configuration/SetPublicationViewController.swift
index f0c39a8bc..84b01a4a2 100644
--- a/Example/nRFMeshProvision/View Controllers/Network/Configuration/SetPublicationViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Network/Configuration/SetPublicationViewController.swift
@@ -189,12 +189,13 @@ private extension SetPublicationViewController {
message: "TTL = Time To Live\n\nTTL limits the number of times a message can be relayed.\nMax value is 127. Message with TTL 0 will not be relayed.",
text: "5", placeHolder: "Default is 5",
type: .ttlRequired,
- option: UIAlertAction(title: "Use Node's default", style: .default, handler: { _ in
+ option: UIAlertAction(title: "Use Node's default", style: .default) { _ in
self.ttl = 0xFF
- }),
+ },
handler: { value in
self.ttl = UInt8(value)!
- })
+ }
+ )
}
func periodSelected(_ period: Float) {
diff --git a/Example/nRFMeshProvision/View Controllers/Network/Provisioning/OobSelector.swift b/Example/nRFMeshProvision/View Controllers/Network/Provisioning/OobSelector.swift
index 50d1d1374..6ddeb463a 100644
--- a/Example/nRFMeshProvision/View Controllers/Network/Provisioning/OobSelector.swift
+++ b/Example/nRFMeshProvision/View Controllers/Network/Provisioning/OobSelector.swift
@@ -60,23 +60,23 @@ extension OobSelector where Self: UIViewController {
}
let alert = UIAlertController(title: "Select OOB Type", message: nil, preferredStyle: .actionSheet)
- alert.addAction(UIAlertAction(title: "No OOB", style: .destructive, handler: { _ in
+ alert.addAction(UIAlertAction(title: "No OOB", style: .destructive) { _ in
callback(.noOob)
- }))
+ })
if capabilities.staticOobType.contains(.staticOobInformationAvailable) {
- alert.addAction(UIAlertAction(title: "Static OOB", style: .default, handler: { _ in
+ alert.addAction(UIAlertAction(title: "Static OOB", style: .default) { _ in
callback(.staticOob)
- }))
+ })
}
if !capabilities.outputOobActions.isEmpty {
- alert.addAction(UIAlertAction(title: "Output OOB", style: .default, handler: { _ in
+ alert.addAction(UIAlertAction(title: "Output OOB", style: .default) { _ in
self.presentOutputOobOptionsDialog(for: provisioningManager, from: item, callback: callback)
- }))
+ })
}
if !capabilities.inputOobActions.isEmpty {
- alert.addAction(UIAlertAction(title: "Input OOB", style: .default, handler: { _ in
+ alert.addAction(UIAlertAction(title: "Input OOB", style: .default) { _ in
self.presentInputOobOptionsDialog(for: provisioningManager, from: item, callback: callback)
- }))
+ })
}
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
alert.popoverPresentationController?.barButtonItem = item
diff --git a/Example/nRFMeshProvision/View Controllers/Network/Provisioning/ProvisioningViewController.swift b/Example/nRFMeshProvision/View Controllers/Network/Provisioning/ProvisioningViewController.swift
index 665f016a7..7b5d5bf66 100644
--- a/Example/nRFMeshProvision/View Controllers/Network/Provisioning/ProvisioningViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Network/Provisioning/ProvisioningViewController.swift
@@ -159,7 +159,8 @@ private extension ProvisioningViewController {
/// Presents a dialog to edit or unbind the Provisioner Unicast Address.
func presentUnicastAddressDialog() {
let manager = self.provisioningManager!
- let action = UIAlertAction(title: "Automatic", style: .default) { _ in
+ let action = UIAlertAction(title: "Automatic", style: .default) { [weak self] _ in
+ guard let self = self else { return }
manager.unicastAddress = manager.suggestedUnicastAddress
self.unicastAddressLabel.text = manager.unicastAddress?.asString() ?? "Automatic"
let deviceSupported = manager.isDeviceSupported == true
@@ -168,7 +169,8 @@ private extension ProvisioningViewController {
}
presentTextAlert(title: "Unicast address", message: "Hexadecimal value in Provisioner's range.",
text: manager.unicastAddress?.hex, placeHolder: "Address", type: .unicastAddressRequired,
- option: action, cancelHandler: nil) { text in
+ option: action, cancelHandler: nil) { [weak self] text in
+ guard let self = self else { return }
manager.unicastAddress = Address(text, radix: 16)
self.unicastAddressLabel.text = manager.unicastAddress!.asString()
let deviceSupported = manager.isDeviceSupported == true
@@ -181,7 +183,8 @@ private extension ProvisioningViewController {
}
func presentStatusDialog(message: String, animated flag: Bool = true, completion: (() -> Void)? = nil) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
if let alert = self.alert {
alert.message = message
completion?()
@@ -197,7 +200,8 @@ private extension ProvisioningViewController {
}
func dismissStatusDialog(completion: (() -> Void)? = nil) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
if let alert = self.alert {
alert.dismiss(animated: true, completion: completion)
} else {
@@ -208,7 +212,8 @@ private extension ProvisioningViewController {
}
func abort() {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
self.alert?.title = "Aborting"
self.alert?.message = "Cancelling connection..."
self.bearer.close()
@@ -248,7 +253,8 @@ private extension ProvisioningViewController {
let outputOobNotSupported = capabilities.outputOobActions.isEmpty
let inputOobNotSupported = capabilities.inputOobActions.isEmpty
guard (staticOobNotSupported && outputOobNotSupported && inputOobNotSupported) || authenticationMethod != nil else {
- presentOobOptionsDialog(for: provisioningManager, from: provisionButton) { method in
+ presentOobOptionsDialog(for: provisioningManager, from: provisionButton) { [weak self] method in
+ guard let self = self else { return }
self.authenticationMethod = method
self.startProvisioning()
}
@@ -291,7 +297,8 @@ extension ProvisioningViewController: GattBearerDelegate {
}
func bearerDidOpen(_ bearer: Bearer) {
- presentStatusDialog(message: "Identifying...") {
+ presentStatusDialog(message: "Identifying...") { [weak self] in
+ guard let self = self else { return }
do {
try self.provisioningManager!.identify(andAttractFor: ProvisioningViewController.attentionTimer)
} catch {
@@ -303,15 +310,17 @@ extension ProvisioningViewController: GattBearerDelegate {
func bearer(_ bearer: Bearer, didClose error: Error?) {
guard case .complete = provisioningManager.state else {
- dismissStatusDialog {
- self.presentAlert(title: "Status", message: "Device disconnected.")
+ dismissStatusDialog { [weak self] in
+ self?.presentAlert(title: "Status", message: "Device disconnected.")
}
return
}
dismissStatusDialog {
- self.presentAlert(title: "Success", message: "Provisioning complete.") { _ in
+ self.presentAlert(title: "Success", message: "Provisioning complete.") { [weak self] _ in
+ guard let self = self else { return }
if MeshNetworkManager.instance.save() {
- self.dismiss(animated: true) {
+ self.dismiss(animated: true) { [weak self] in
+ guard let self = self else { return }
let network = MeshNetworkManager.instance.meshNetwork!
if let node = network.node(for: self.unprovisionedDevice) {
self.delegate?.provisionerDidProvisionNewDevice(node)
@@ -329,7 +338,8 @@ extension ProvisioningViewController: GattBearerDelegate {
extension ProvisioningViewController: ProvisioningDelegate {
func provisioningState(of unprovisionedDevice: UnprovisionedDevice, didChangeTo state: ProvisioningState) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
switch state {
case .requestingCapabilities:
diff --git a/Example/nRFMeshProvision/View Controllers/Network/Provisioning/ScannerTableViewController.swift b/Example/nRFMeshProvision/View Controllers/Network/Provisioning/ScannerTableViewController.swift
index 26a2a5a72..61e182eb3 100644
--- a/Example/nRFMeshProvision/View Controllers/Network/Provisioning/ScannerTableViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Network/Provisioning/ScannerTableViewController.swift
@@ -116,7 +116,7 @@ class ScannerTableViewController: UITableViewController {
selectedDevice = discoveredPeripherals[indexPath.row].device
alert = UIAlertController(title: "Status", message: "Connecting...", preferredStyle: .alert)
- alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel) { [weak self, bearer] action in
+ alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel) { [weak self] action in
action.isEnabled = false
self?.alert?.title = "Aborting"
self?.alert?.message = "Cancelling connection..."
diff --git a/Example/nRFMeshProvision/View Controllers/ProgressCollectionViewController.swift b/Example/nRFMeshProvision/View Controllers/ProgressCollectionViewController.swift
index 0d21aefac..b8f02158f 100644
--- a/Example/nRFMeshProvision/View Controllers/ProgressCollectionViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/ProgressCollectionViewController.swift
@@ -57,7 +57,8 @@ class ProgressCollectionViewController: UICollectionViewController {
/// - parameter message: Message to be displayed to the user.
/// - parameter completion: A completion handler.
func start(_ message: String, completion: @escaping () throws -> MessageHandle?) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
do {
self.messageHandle = try completion()
guard let _ = self.messageHandle else {
@@ -71,9 +72,9 @@ class ProgressCollectionViewController: UICollectionViewController {
self.alert = UIAlertController(title: "Status",
message: message,
preferredStyle: .alert)
- self.alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
- self.messageHandle?.cancel()
- self.alert = nil
+ self.alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel) { [weak self] _ in
+ self?.messageHandle?.cancel()
+ self?.alert = nil
})
self.present(self.alert!, animated: true)
}
@@ -83,8 +84,8 @@ class ProgressCollectionViewController: UICollectionViewController {
self.alert = UIAlertController(title: "Error",
message: error.localizedDescription,
preferredStyle: .alert)
- self.alert!.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in
- self.alert = nil
+ self.alert!.addAction(UIAlertAction(title: "OK", style: .cancel) { [weak self] _ in
+ self?.alert = nil
})
self.present(self.alert!, animated: true)
}
diff --git a/Example/nRFMeshProvision/View Controllers/ProgressViewController.swift b/Example/nRFMeshProvision/View Controllers/ProgressViewController.swift
index 329df4c41..af93f378c 100644
--- a/Example/nRFMeshProvision/View Controllers/ProgressViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/ProgressViewController.swift
@@ -57,14 +57,15 @@ class ProgressViewController: UITableViewController {
/// - parameter message: Message to be displayed to the user.
/// - parameter completion: A completion handler.
func start(_ message: String, completion: @escaping () -> Void) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
if let alert = self.alert {
alert.message = message
} else {
self.alert = UIAlertController(title: "Status", message: message, preferredStyle: .alert)
- self.alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: {
- _ in self.alert = nil
- }))
+ self.alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel) {
+ [weak self] _ in self?.alert = nil
+ })
self.present(self.alert!, animated: true)
}
@@ -78,7 +79,8 @@ class ProgressViewController: UITableViewController {
/// - parameter message: Message to be displayed to the user.
/// - parameter completion: A completion handler.
func start(_ message: String, completion: @escaping () throws -> MessageHandle?) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
do {
self.messageHandle = try completion()
guard let _ = self.messageHandle else {
@@ -92,10 +94,10 @@ class ProgressViewController: UITableViewController {
self.alert = UIAlertController(title: "Status",
message: message,
preferredStyle: .alert)
- self.alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
- self.messageHandle?.cancel()
- self.alert = nil
- self.refreshControl?.endRefreshing()
+ self.alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel) { [weak self] _ in
+ self?.messageHandle?.cancel()
+ self?.alert = nil
+ self?.refreshControl?.endRefreshing()
})
self.present(self.alert!, animated: true)
}
@@ -113,8 +115,8 @@ class ProgressViewController: UITableViewController {
self.alert = UIAlertController(title: "Error",
message: error.localizedDescription,
preferredStyle: .alert)
- self.alert!.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in
- self.alert = nil
+ self.alert!.addAction(UIAlertAction(title: "OK", style: .cancel) { [weak self] _ in
+ self?.alert = nil
})
self.present(self.alert!, animated: true)
}
diff --git a/Example/nRFMeshProvision/View Controllers/Proxy/ProxySelectorViewController.swift b/Example/nRFMeshProvision/View Controllers/Proxy/ProxySelectorViewController.swift
index 70efdf7ed..6d104b168 100644
--- a/Example/nRFMeshProvision/View Controllers/Proxy/ProxySelectorViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Proxy/ProxySelectorViewController.swift
@@ -103,10 +103,10 @@ class ProxySelectorViewController: UITableViewController {
selectedDevice = bearer
alert = UIAlertController(title: "Status", message: "Connecting...", preferredStyle: .alert)
- alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel) { action in
+ alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel) { [weak self] action in
action.isEnabled = false
- self.alert!.title = "Aborting"
- self.alert!.message = "Cancelling connection..."
+ self?.alert?.title = "Aborting"
+ self?.alert?.message = "Cancelling connection..."
bearer.close()
})
present(alert!, animated: true) {
@@ -176,29 +176,30 @@ extension ProxySelectorViewController: CBCentralManagerDelegate {
extension ProxySelectorViewController: GattBearerDelegate {
func bearerDidConnect(_ bearer: Bearer) {
- DispatchQueue.main.async {
- self.alert?.message = "Discovering services..."
+ DispatchQueue.main.async { [weak self] in
+ self?.alert?.message = "Discovering services..."
}
}
func bearerDidDiscoverServices(_ bearer: Bearer) {
- DispatchQueue.main.async {
- self.alert?.message = "Initializing..."
+ DispatchQueue.main.async { [weak self] in
+ self?.alert?.message = "Initializing..."
}
}
func bearerDidOpen(_ bearer: Bearer) {
MeshNetworkManager.bearer.use(proxy: bearer as! GattBearer)
- DispatchQueue.main.async {
- self.alert?.dismiss(animated: true) {
- self.dismiss(animated: true)
+ DispatchQueue.main.async { [weak self] in
+ self?.alert?.dismiss(animated: true) { [weak self] in
+ self?.dismiss(animated: true)
}
- self.alert = nil
+ self?.alert = nil
}
}
func bearer(_ bearer: Bearer, didClose error: Error?) {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
self.alert?.message = "Device disconnected"
self.alert?.dismiss(animated: true)
self.alert = nil
diff --git a/Example/nRFMeshProvision/View Controllers/Settings/AppKeysViewController.swift b/Example/nRFMeshProvision/View Controllers/Settings/AppKeysViewController.swift
index 5adfc7201..cbd45088f 100644
--- a/Example/nRFMeshProvision/View Controllers/Settings/AppKeysViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Settings/AppKeysViewController.swift
@@ -41,9 +41,10 @@ class AppKeysViewController: UITableViewController, Editable {
} else {
presentAlert(title: "Error",
message: "No Network Key found.\n\nCreate a Network Key prior to creating an Application Key.",
- option: UIAlertAction(title: "Create", style: .default, handler: { action in
- self.performSegue(withIdentifier: "networkKeys", sender: nil)
- }))
+ option: UIAlertAction(title: "Create", style: .default) { [weak self] action in
+ self?.performSegue(withIdentifier: "networkKeys", sender: nil)
+ }
+ )
}
}
@@ -55,7 +56,8 @@ class AppKeysViewController: UITableViewController, Editable {
self.presentTextAlert(title: "Generate keys",
message: "Specify number of application keys to generate (max 5):",
placeHolder: "E.g. 3", type: .numberRequired,
- cancelHandler: nil) { value in
+ cancelHandler: nil) { [weak self] value in
+ guard let self = self else { return }
guard let network = MeshNetworkManager.instance.meshNetwork,
let number = Int(value), number > 0 else {
return
diff --git a/Example/nRFMeshProvision/View Controllers/Settings/ExportViewController.swift b/Example/nRFMeshProvision/View Controllers/Settings/ExportViewController.swift
index 9bb07defc..54cc09a59 100644
--- a/Example/nRFMeshProvision/View Controllers/Settings/ExportViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Settings/ExportViewController.swift
@@ -265,7 +265,8 @@ private extension ExportViewController {
func exportNetwork(using exportConfiguration: ExportConfiguration) {
let manager = MeshNetworkManager.instance
- DispatchQueue.global(qos: .userInitiated).async {
+ DispatchQueue.global(qos: .userInitiated).async { [weak self] in
+ guard let self = self else { return }
let data = manager.export(exportConfiguration)
do {
@@ -273,10 +274,12 @@ private extension ExportViewController {
let fileURL = FileManager.default.temporaryDirectory.appendingPathComponent("\(name).json")
try data.write(to: fileURL)
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
let controller = UIActivityViewController(activityItems: [fileURL], applicationActivities: nil)
controller.popoverPresentationController?.barButtonItem = self.doneButton
- controller.completionWithItemsHandler = { type, success, items, error in
+ controller.completionWithItemsHandler = { [weak self] type, success, items, error in
+ guard let self = self else { return }
if success {
self.dismiss(animated: true)
} else {
@@ -292,10 +295,10 @@ private extension ExportViewController {
}
} catch {
print("Export failed: \(error)")
- DispatchQueue.main.async {
- self.presentAlert(title: "Error",
- message: "Exporting Mesh Network configuration failed "
- + "with error \(error.localizedDescription).")
+ DispatchQueue.main.async { [weak self] in
+ self?.presentAlert(title: "Error",
+ message: "Exporting Mesh Network configuration failed "
+ + "with error \(error.localizedDescription).")
}
}
}
diff --git a/Example/nRFMeshProvision/View Controllers/Settings/Provisioners/EditProvisionerViewController.swift b/Example/nRFMeshProvision/View Controllers/Settings/Provisioners/EditProvisionerViewController.swift
index 6a6215fd7..d1797c216 100644
--- a/Example/nRFMeshProvision/View Controllers/Settings/Provisioners/EditProvisionerViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Settings/Provisioners/EditProvisionerViewController.swift
@@ -233,7 +233,8 @@ private extension EditProvisionerViewController {
let nodeAssigned = newAddress != nil || (node != nil && !disableConfigCapabilities)
let action = !nodeAssigned ? nil : UIAlertAction(title: "Unassign", style: .destructive) { action in
self.confirm(title: "Disable configuration capabilities",
- message: "A Provisioner without the unicast address assigned is not able to perform configuration operations.") { _ in
+ message: "A Provisioner without the unicast address assigned is not able to perform configuration operations.") { [weak self] _ in
+ guard let self = self else { return }
self.disableConfigCapabilities = true
self.newAddress = nil
self.unicastAddressLabel.text = "Not assigned"
@@ -246,7 +247,8 @@ private extension EditProvisionerViewController {
}
presentTextAlert(title: "Unicast address", message: "Hexadecimal value in range\n0001 - 7FFF.",
text: address, placeHolder: "Address", type: .unicastAddressRequired,
- option: action, cancelHandler: nil) { text in
+ option: action, cancelHandler: nil) { [weak self] text in
+ guard let self = self else { return }
let address = Address(text, radix: 16)
self.unicastAddressLabel.text = address!.asString()
self.disableConfigCapabilities = false
@@ -272,7 +274,8 @@ private extension EditProvisionerViewController {
presentTextAlert(title: "Default TTL",
message: "TTL = Time To Live\n\nTTL limits the number of times a message can be relayed.\nMax value is 127.",
text: "\(node?.defaultTTL ?? 5)", placeHolder: "Default is 5",
- type: .ttlRequired, cancelHandler: nil) { value in
+ type: .ttlRequired, cancelHandler: nil) { [weak self] value in
+ guard let self = self else { return }
let ttl = UInt8(value)!
self.newTtl = ttl
self.ttlCell.detailTextLabel?.text = "\(ttl)"
@@ -361,9 +364,9 @@ private extension EditProvisionerViewController {
let nextText = next.map { " Next available address is \($0.asString())."} ??
" No available addresses. Extend the unicast address range to assign a new one."
let autoAssign = next.map { nextAddress in
- UIAlertAction(title: "Assign", style: .default) { _ in
- self.newAddress = nextAddress
- self.unicastAddressLabel.text = nextAddress.asString()
+ UIAlertAction(title: "Assign", style: .default) { [weak self] _ in
+ self?.newAddress = nextAddress
+ self?.unicastAddressLabel.text = nextAddress.asString()
}
}
presentAlert(title: "Error",
@@ -377,9 +380,9 @@ private extension EditProvisionerViewController {
let nextText = next.map { " Next available address is \($0.asString())."} ??
" No available addresses. Extend the unicast address range to assign a new one."
let autoAssign = next.map { nextAddress in
- UIAlertAction(title: "Assign", style: .default) { _ in
- self.newAddress = nextAddress
- self.unicastAddressLabel.text = nextAddress.asString()
+ UIAlertAction(title: "Assign", style: .default) { [weak self] _ in
+ self?.newAddress = nextAddress
+ self?.unicastAddressLabel.text = nextAddress.asString()
}
}
presentAlert(title: "Error", message: "The address range \(address.asString())...\((address + UInt16(count) - 1).hex) is already in use or is reserved. A unique unicast address must be assigned to each of the \(count) elements.\(nextText)", option: autoAssign)
diff --git a/Example/nRFMeshProvision/View Controllers/Settings/SettingsViewController.swift b/Example/nRFMeshProvision/View Controllers/Settings/SettingsViewController.swift
index 0eb87ee24..0ca631451 100644
--- a/Example/nRFMeshProvision/View Controllers/Settings/SettingsViewController.swift
+++ b/Example/nRFMeshProvision/View Controllers/Settings/SettingsViewController.swift
@@ -148,7 +148,7 @@ private extension SettingsViewController {
message: "Resetting the network will erase all network data.\n"
+ "Make sure you exported it first.",
preferredStyle: .actionSheet)
- let resetAction = UIAlertAction(title: "Reset", style: .destructive) { _ in self.resetNetwork() }
+ let resetAction = UIAlertAction(title: "Reset", style: .destructive) { [weak self] _ in self?.resetNetwork() }
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
alert.addAction(resetAction)
alert.addAction(cancelAction)
@@ -162,8 +162,8 @@ private extension SettingsViewController {
message: "Importing network will override your existing settings.\n"
+ "Make sure you exported it first.",
preferredStyle: .actionSheet)
- let exportAction = UIAlertAction(title: "Export", style: .default) { _ in self.exportNetwork() }
- let importAction = UIAlertAction(title: "Import", style: .destructive) { _ in self.importNetwork() }
+ let exportAction = UIAlertAction(title: "Export", style: .default) { [weak self] _ in self?.exportNetwork() }
+ let importAction = UIAlertAction(title: "Import", style: .destructive) { [weak self] _ in self?.importNetwork() }
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
alert.addAction(exportAction)
alert.addAction(importAction)
@@ -223,7 +223,8 @@ private extension SettingsViewController {
/// Saves mesh network configuration and reloads network data on success.
func saveAndReload() {
if MeshNetworkManager.instance.save() {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
(UIApplication.shared.delegate as! AppDelegate).meshNetworkDidChange()
self.reload()
self.presentAlert(title: "Success", message: "Mesh Network configuration imported.")
@@ -241,7 +242,8 @@ extension SettingsViewController: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
let manager = MeshNetworkManager.instance
- DispatchQueue.global(qos: .userInitiated).async {
+ DispatchQueue.global(qos: .userInitiated).async { [weak self] in
+ guard let self = self else { return }
do {
let data = try Data(contentsOf: url)
let meshNetwork = try manager.import(from: data)
@@ -250,17 +252,18 @@ extension SettingsViewController: UIDocumentPickerDelegate {
// If it's a new network and has only one Provisioner, just save it.
// Otherwise, give the user option to select one.
if meshNetwork.provisioners.count > 1 {
- DispatchQueue.main.async {
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
let alert = UIAlertController(title: "Select Provisioner",
message: "Select Provisioner instance to be used on this device:",
preferredStyle: .actionSheet)
alert.popoverPresentationController?.barButtonItem = self.organizeButton
for provisioner in meshNetwork.provisioners {
- alert.addAction(UIAlertAction(title: provisioner.name, style: .default) { action in
+ alert.addAction(UIAlertAction(title: provisioner.name, style: .default) { [weak self] action in
// This will effectively set the Provisioner to be used
// be the library. Provisioner from index 0 is the local one.
meshNetwork.moveProvisioner(provisioner, toIndex: 0)
- self.saveAndReload()
+ self?.saveAndReload()
})
}
self.present(alert, animated: true)
@@ -272,41 +275,41 @@ extension SettingsViewController: UIDocumentPickerDelegate {
} catch let DecodingError.dataCorrupted(context) {
let path = context.codingPath.path
print("Import failed: \(context.debugDescription) (\(path))")
- DispatchQueue.main.async {
- self.presentAlert(title: "Error",
- message: "Importing Mesh Network configuration failed.\n"
- + "\(context.debugDescription)\nPath: \(path).")
+ DispatchQueue.main.async { [weak self] in
+ self?.presentAlert(title: "Error",
+ message: "Importing Mesh Network configuration failed.\n"
+ + "\(context.debugDescription)\nPath: \(path).")
}
} catch let DecodingError.keyNotFound(key, context) {
let path = context.codingPath.path
print("Import failed: Key \(key) not found in \(path)")
- DispatchQueue.main.async {
- self.presentAlert(title: "Error",
- message: "Importing Mesh Network configuration failed.\n"
- + "No value associated with key: \(key.stringValue) in: \(path).")
+ DispatchQueue.main.async { [weak self] in
+ self?.presentAlert(title: "Error",
+ message: "Importing Mesh Network configuration failed.\n"
+ + "No value associated with key: \(key.stringValue) in: \(path).")
}
} catch let DecodingError.valueNotFound(value, context) {
let path = context.codingPath.path
print("Import failed: Value of type \(value) required in \(path)")
- DispatchQueue.main.async {
- self.presentAlert(title: "Error",
- message: "Importing Mesh Network configuration failed.\n"
- + "No value associated with key: \(path).")
+ DispatchQueue.main.async { [weak self] in
+ self?.presentAlert(title: "Error",
+ message: "Importing Mesh Network configuration failed.\n"
+ + "No value associated with key: \(path).")
}
} catch let DecodingError.typeMismatch(type, context) {
let path = context.codingPath.path
print("Import failed: Type mismatch in \(path) (\(type) was required)")
- DispatchQueue.main.async {
- self.presentAlert(title: "Error",
- message: "Importing Mesh Network configuration failed.\n"
- + "Type mismatch in: \(path). Expected: \(type).")
+ DispatchQueue.main.async { [weak self] in
+ self?.presentAlert(title: "Error",
+ message: "Importing Mesh Network configuration failed.\n"
+ + "Type mismatch in: \(path). Expected: \(type).")
}
} catch {
print("Import failed: \(error)")
- DispatchQueue.main.async {
- self.presentAlert(title: "Error",
- message: "Importing Mesh Network configuration failed.\n"
- + "Check if the file is valid.")
+ DispatchQueue.main.async { [weak self] in
+ self?.presentAlert(title: "Error",
+ message: "Importing Mesh Network configuration failed.\n"
+ + "Check if the file is valid.")
}
}
}
diff --git a/nRFMeshProvision.podspec b/nRFMeshProvision.podspec
index b9c75b655..528821104 100755
--- a/nRFMeshProvision.podspec
+++ b/nRFMeshProvision.podspec
@@ -9,7 +9,7 @@
Pod::Spec.new do |s|
s.name = 'nRFMeshProvision'
- s.version = '3.1.3'
+ s.version = '3.1.4'
s.summary = 'A Bluetooth Mesh library'
s.description = <<-DESC
nRF Mesh is a Bluetooth Mesh compliant library that has many features such as provisioning, configuration and control of Bluetooth Mesh compliant nodes.
@@ -26,7 +26,4 @@ Pod::Spec.new do |s|
s.source_files = 'nRFMeshProvision/Classes/**/*'
s.dependency 'CryptoSwift', '= 1.4.0'
s.frameworks = 'CoreBluetooth'
- # Regarding the lines below see: https://stackoverflow.com/a/63955114/2115352
- # s.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
- # s.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
end
diff --git a/nRFMeshProvision/Classes/Mesh Model/IvIndex.swift b/nRFMeshProvision/Classes/Mesh Model/IvIndex.swift
index 63f19fea6..fbae19568 100644
--- a/nRFMeshProvision/Classes/Mesh Model/IvIndex.swift
+++ b/nRFMeshProvision/Classes/Mesh Model/IvIndex.swift
@@ -58,7 +58,7 @@ internal struct IvIndex {
/// - parameter ivi: The IVI bit of the received Network PDU.
/// - returns: The IV Index to be used to decrypt the message.
func index(for ivi: UInt8) -> UInt32 {
- return ivi == index & 1 ? index : index - 1
+ return ivi == index & 1 ? index : max(1, index) - 1
}
}
diff --git a/nRFMeshProvision/Classes/Mesh Model/MeshNetwork.swift b/nRFMeshProvision/Classes/Mesh Model/MeshNetwork.swift
index ec09eeb61..740b210b3 100644
--- a/nRFMeshProvision/Classes/Mesh Model/MeshNetwork.swift
+++ b/nRFMeshProvision/Classes/Mesh Model/MeshNetwork.swift
@@ -357,7 +357,9 @@ public class MeshNetwork: Codable {
debugDescription: "Device Key cannot be empty in non-partial configuration.")
}
nodes = ns
- groups = try container.decode([Group].self, forKey: .groups)
+ // Groups are mandatory, but one of the Android versions didn't export empty
+ // list to JSON, so it may happen that Groups are `nil`.
+ groups = try container.decodeIfPresent([Group].self, forKey: .groups) ?? []
networkExclusions = try container.decodeIfPresent([ExclusionList].self, forKey: .networkExclusions)
// Scenes are mandatory, but previous version of the library did support it,
// so JSON files generated with such versions won't have "scenes" tag.