Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade swift version to 6 for Data layer target #192

Conversation

pantelisss
Copy link
Collaborator

@pantelisss pantelisss commented Nov 28, 2024

Why?

Upgrade Data layer to Swif 6

How?

Fixed all errors regarding the Swift 6

Testing

Ensure the app builds and works as expected

Additional context

Fixes FE-1351

Summary by CodeRabbit

  • New Features

    • Introduced a claim device flow with sub-views and view models.
    • Added detailed reward information screens and analytics.
    • Implemented a new weather forecast feature with temperature charts.
    • Added a grid-based layout for displaying network statistics.
    • Introduced a device information screen showing connection status and health.
    • Added utility components including loaders and custom alerts.
    • Enhanced localization and internationalization support.
  • Bug Fixes

    • Improved concurrency handling across various components.
  • Documentation

    • Updated documentation to reflect new features and changes in concurrency handling.
  • Chores

    • Updated project settings and configurations for Swift 6.0 and concurrency support.

Copy link

coderabbitai bot commented Nov 28, 2024

Walkthrough

The changes in this pull request primarily involve modifications to various Swift files to enhance concurrency support and update protocol conformances. Key updates include the addition of @retroactive attributes for protocol conformance in several extensions, the introduction of nonisolated(unsafe) attributes to certain static properties, and updates to import statements to utilize @preconcurrency. Additionally, several classes and structs have been marked as @unchecked Sendable, allowing them to be used safely in concurrent contexts. These changes collectively aim to improve the handling of concurrency across the codebase.

Changes

File Path Change Summary
PresentationLayer/Constants/WeatherFields.swift Updated WeatherField extension to conform to @retroactive CustomStringConvertible.
PresentationLayer/Extensions/DomainExtensions/Common/CurrentWeather+.swift Updated CurrentWeather extension to conform to @retroactive Identifiable.
PresentationLayer/Extensions/DomainExtensions/Common/UserDeviceFollowState+.swift Added nonisolated(unsafe) to defaultFAIcon property in UserDeviceFollowState extension.
PresentationLayer/UIComponents/BaseComponents/WeatherOverview/WeatherOverviewView+Content.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
PresentationLayer/UIComponents/BaseComponents/WeatherOverview/WeatherOverviewView.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
PresentationLayer/UIComponents/Modifiers/SizeObserver.swift Added nonisolated(unsafe) to defaultValue property in FramePreferenceKey struct.
PresentationLayer/Utils/Weather/WeatherUnitsManager.swift Added nonisolated(unsafe) to default property in WeatherUnitsManager class.
station-intent/IntentHandler.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
station-widget/Extensions/DeviceDetails+Widget.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
station-widget/StationTimelineEntry.swift Added @unchecked Sendable to StationTimelineEntry struct; changed import of DomainLayer.
station-widget/Station_widget.swift Added @unchecked Sendable to Provider struct; updated getTimeline and getEntry method signatures.
station-widget/Views/ErrorView.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
station-widget/Views/StationWidgetView.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
wxm-ios.xcodeproj/project.pbxproj Various updates including new features and improvements across the codebase.
wxm-ios.xcodeproj/xcshareddata/xcschemes/station-intent.xcscheme Updated LastUpgradeVersion from "1530" to "1610".
wxm-ios.xcodeproj/xcshareddata/xcschemes/station-widgetExtension.xcscheme Updated LastUpgradeVersion from "1530" to "1610".
wxm-ios.xcodeproj/xcshareddata/xcschemes/wxm-ios-db.xcscheme Updated LastUpgradeVersion from "1530" to "1610".
wxm-ios.xcodeproj/xcshareddata/xcschemes/wxm-ios-mock.xcscheme Updated LastUpgradeVersion from "1530" to "1610".
wxm-ios.xcodeproj/xcshareddata/xcschemes/wxm-ios-release.xcscheme Updated LastUpgradeVersion from "1530" to "1610".
wxm-ios.xcodeproj/xcshareddata/xcschemes/wxm-ios.xcscheme Updated LastUpgradeVersion from "1530" to "1610".
wxm-ios/DataLayer/DataLayer.xcodeproj/project.pbxproj Updated LastUpgradeCheck from 1530 to 1610, updated Swift version to 6.0, added SWIFT_STRICT_CONCURRENCY.
wxm-ios/DataLayer/DataLayer.xcodeproj/xcshareddata/xcschemes/DataLayer.xcscheme Updated LastUpgradeVersion from "1530" to "1610".
wxm-ios/DataLayer/DataLayer/Database/DatabaseService.swift Added nonisolated(unsafe) to shared property in DatabaseService class.
wxm-ios/DataLayer/DataLayer/Networking/ApiClient.swift Added nonisolated(unsafe) to shared property in ApiClient class.
wxm-ios/DataLayer/DataLayer/Networking/ApiRequestBuilders/MeApiRequestBuilder.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
wxm-ios/DataLayer/DataLayer/Networking/Interceptors/AuthInterceptor.swift Added @unchecked Sendable to AuthInterceptor class; updated import statements to @preconcurrency.
wxm-ios/DataLayer/DataLayer/Networking/Interceptors/RequestHeadersAdapter.swift Updated method signatures for concurrency support; refactored generateClientId method to async.
wxm-ios/DataLayer/DataLayer/Networking/Mock/MockProtocol.swift Added @unchecked Sendable to MockProtocol class; added nonisolated(unsafe) to responses variable.
wxm-ios/DataLayer/DataLayer/RepositoryImplementations/AuthRepositoryImpl.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
wxm-ios/DataLayer/DataLayer/RepositoryImplementations/Bluetooth/BTActionsWrapper.swift Added @unchecked Sendable to BTActionWrapper class; updated method signatures for concurrency.
wxm-ios/DataLayer/DataLayer/RepositoryImplementations/DeviceInfoRepositoryImpl.swift Added @unchecked Sendable to DeviceInfoRepositoryImpl class; updated property for concurrency.
wxm-ios/DataLayer/DataLayer/RepositoryImplementations/DevicesRepositoryImpl.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
wxm-ios/DataLayer/DataLayer/RepositoryImplementations/ExplorerRepositoryImpl.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
wxm-ios/DataLayer/DataLayer/RepositoryImplementations/FirmwareUpdateImpl.swift Added @unchecked Sendable to FirmwareUpdateImpl class.
wxm-ios/DataLayer/DataLayer/RepositoryImplementations/LocationRepositoryImpl.swift Changed import of MapboxSearch to @preconcurrency import MapboxSearch.
wxm-ios/DataLayer/DataLayer/RepositoryImplementations/MeRepositoryImpl.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
wxm-ios/DataLayer/DataLayer/RepositoryImplementations/NetworkRepositoryImpl.swift Changed import of DomainLayer to @preconcurrency import DomainLayer.
wxm-ios/DataLayer/UserDevicesService.swift Added @unchecked Sendable to UserDevicesService class; introduced getFollowStates() method.
wxm-ios/DataLayer/UserInfoService.swift Added @unchecked Sendable to UserInfoService class.
wxm-ios/DomainLayer/DomainLayer.xcodeproj/project.pbxproj Updated build settings and configurations, including ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS.
wxm-ios/DomainLayer/DomainLayer/DomainRepositoryInterfaces/BluetoothDevicesRepository.swift Updated enums and structs to conform to Sendable.
wxm-ios/DomainLayer/DomainLayer/DomainRepositoryInterfaces/DeviceInfoRepository.swift Updated enums to conform to Sendable.
wxm-ios/DomainLayer/DomainLayer/DomainRepositoryInterfaces/MeRepository.swift Added Sendable conformance to UserDeviceFollowState struct.
wxm-ios/DomainLayer/DomainLayer/Entities/Codables/Devices/NetworkDevicesTypes.swift Updated DeviceRelation enum to conform to Sendable; modified initializers for StationBundle and Metrics.
wxm-ios/DomainLayer/DomainLayer/Entities/Codables/Me/Body/ClaimDeviceBody.swift Updated dictionaryRepresentation to return [String: Any & Sendable].
wxm-ios/DomainLayer/DomainLayer/Entities/DomainModels/DeviceDetails.swift Added @unchecked Sendable to DeviceDetails struct.
wxm-ios/DomainLayer/DomainLayer/UseCases/WidgetUseCase.swift Added @MainActor to getDevices method.
wxm-ios/Swinject/SwinjectHelper.swift Updated import statements to @preconcurrency; added nonisolated(unsafe) to shared property.
wxm-ios/Toolkit/Toolkit.xcodeproj/project.pbxproj Updated build settings and configurations, including SWIFT_VERSION to 6.0.
wxm-ios/Toolkit/Toolkit.xcodeproj/xcshareddata/xcschemes/Toolkit.xcscheme Updated LastUpgradeVersion from "1530" to "1610".
wxm-ios/Toolkit/Toolkit/Analytics/WXMAnalytics.swift Added @unchecked Sendable to WXMAnalytics class.
wxm-ios/Toolkit/Toolkit/FirebaseManager/FirebaseManager.swift Added @unchecked Sendable to FirebaseManager class; corrected type declaration.
wxm-ios/Toolkit/Toolkit/FirebaseManager/NotificationsHandler.swift Updated to conform to Sendable; modified method signatures for concurrency.
wxm-ios/Toolkit/Toolkit/FirebaseManager/RemoteConfigManager.swift Added @unchecked Sendable to RemoteConfigManager class; adjusted property visibility.
wxm-ios/Toolkit/Toolkit/Logger/Logger.swift Added @unchecked Sendable to Logger class.
wxm-ios/Toolkit/Toolkit/Utils/Cancellables.swift Updated storeThreadSafe method to @MainActor.
wxm-ios/Toolkit/Toolkit/Utils/Combine+.swift Updated toAsync method for concurrency handling.
wxm-ios/Toolkit/Toolkit/Utils/Double+.swift Updated toPrecisionString method to use let for clarity; added infix operator ~==.
wxm-ios/Toolkit/Toolkit/Utils/WEIConverter.swift Simplified toEthDecimal method by removing unnecessary local variable.
wxm-ios/Toolkit/Toolkit/Utils/WXMLocationManager.swift Added Sendable conformance to Status enum.

Possibly related PRs

  • Investigate missing dsyms warning from ci jobs #156: This PR addresses issues related to the configuration of the project, including enabling dSym files which may indirectly relate to the changes in the WeatherField extension's string representation, as both involve aspects of the project's structure and debugging capabilities.
  • Chart issue in reward anaytics #172: This PR modifies the RewardAnalyticsChartFactory and related UI components, which may share similar data handling or presentation logic with the WeatherField extension, particularly in how data is represented.
  • Reward analytics fixes #183: This PR includes updates to the reward analytics feature, which may involve similar data representation concerns as the changes made to the WeatherField extension, focusing on how information is displayed to users.

Suggested reviewers

  • PavlosTze: Suggested reviewer for the changes made in this pull request.

🐰 In the fields where we hop and play,
New changes bloom, bright as the day!
With protocols and imports anew,
Our code hops faster, through and through!
Concurrency's dance, we now embrace,
In this code garden, we find our place! 🌼


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@pantelisss pantelisss changed the base branch from main to feature/fe-1352-upgrade-swift-version-to-6-for-widget-target November 28, 2024 15:45
@pantelisss pantelisss requested a review from PavlosTze November 28, 2024 15:45
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

🛑 Comments failed to post (22)
wxm-ios/Toolkit/Toolkit/Utils/Combine+.swift (1)

9-9: 💡 Codebase verification

Swift 6 migration: Add @preconcurrency to all Combine imports

Based on the search results, there are numerous files importing Combine without the @preconcurrency attribute. Since this is a Swift 6 migration, all Combine imports should consistently use @preconcurrency to properly mark potentially unsafe concurrent APIs.

Key locations requiring the same change:

  • wxm-ios/AppCore/MainApp.swift
  • wxm-ios/Toolkit/Toolkit/Utils/WXMLocationManager.swift
  • wxm-ios/Toolkit/Toolkit/Utils/Cancellables.swift
  • All files in wxm-ios/DataLayer/
  • All files in wxm-ios/DomainLayer/
  • All files in PresentationLayer/
🔗 Analysis chain

LGTM: Appropriate use of @preconcurrency attribute

The addition of @preconcurrency to the Combine import is correct for Swift 6 migration, as it properly marks potentially unsafe concurrent APIs.

Let's verify consistent usage across the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for other Combine imports that might need @preconcurrency
rg "^import\s+Combine" --type swift

Length of output: 8614

station-widget/Views/ErrorView.swift (1)

9-9: 💡 Codebase verification

Inconsistent usage of @preconcurrency attribute with DomainLayer imports detected

The verification reveals inconsistent usage of the @preconcurrency attribute across the codebase:

  • Only 20 files use @preconcurrency import DomainLayer
  • Over 120 files use plain import DomainLayer

This inconsistency could lead to potential thread-safety issues during the Swift 6 migration. All imports of DomainLayer should be marked with @preconcurrency as part of the concurrency improvements strategy.

Key locations requiring updates:

  • DataLayer module files (e.g., KeychainHelperService.swift, ApiClient.swift)
  • PresentationLayer module files (e.g., HistoryViewModel.swift, WeatherUnitsConverter.swift)
  • Core app files (e.g., MainApp.swift)
🔗 Analysis chain

LGTM! Consistent with Swift 6 upgrade strategy.

The addition of @preconcurrency to the DomainLayer import aligns with the project's Swift 6 upgrade objectives and broader concurrency improvements.

Let's verify consistent usage across the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent @preconcurrency usage with DomainLayer imports
# Expected: All DomainLayer imports should use @preconcurrency

# Search for DomainLayer imports without @preconcurrency
echo "Checking for non-preconcurrency DomainLayer imports:"
rg "^import\s+DomainLayer\s*$" --type swift

# Search for DomainLayer imports with @preconcurrency
echo -e "\nChecking for preconcurrency DomainLayer imports:"
rg "^@preconcurrency\s+import\s+DomainLayer\s*$" --type swift

Length of output: 17971

wxm-ios/Toolkit/Toolkit/Analytics/WXMAnalytics.swift (1)

10-10: 🛠️ Refactor suggestion

Consider adding synchronization for providers array

While marking the class as @unchecked Sendable, it's important to ensure thread-safe access to shared mutable state.

Consider adding synchronization to protect the providers array:

 public class WXMAnalytics: @unchecked Sendable {
     public static let shared = WXMAnalytics()
-    private var providers: [AnalyticsProviderImplementation] = []
+    private let queue = DispatchQueue(label: "com.wxm.analytics", attributes: .concurrent)
+    private var _providers: [AnalyticsProviderImplementation] = []
+    private var providers: [AnalyticsProviderImplementation] {
+        get { queue.sync { _providers } }
+        set { queue.async(flags: .barrier) { self._providers = newValue } }
+    }

This ensures thread-safe access to the providers array while maintaining good performance through a concurrent queue with barrier writes.

Committable suggestion skipped: line range outside the PR's diff.

PresentationLayer/UIComponents/Modifiers/SizeObserver.swift (1)

47-47: 💡 Codebase verification

Warning: Inconsistent thread-safety annotations in the codebase

The verification revealed two different uses of nonisolated(unsafe):

  1. In SizeObserver.swift: Used safely with an immutable CGRect value
  2. In MockProtocol.swift: Used with a mutable dictionary [String: String], which is not thread-safe

The MockProtocol usage is concerning because:

  • The static dictionary can be modified at runtime
  • Dictionary type is not thread-safe for concurrent access
  • Mutable state should not be marked as nonisolated(unsafe)
🔗 Analysis chain

LGTM! The nonisolated(unsafe) annotation is appropriate here.

The addition of nonisolated(unsafe) to defaultValue is safe because:

  • The value is an immutable CGRect.zero
  • CGRect is a value type, making it thread-safe
  • The property is only read, never modified after initialization

Let's verify similar patterns across the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for similar PreferenceKey implementations to ensure consistent concurrency annotations

# Search for PreferenceKey conformances
ast-grep --pattern 'struct $NAME: PreferenceKey {
  $$$
  static var defaultValue$$$
  $$$
}'

# Search for other nonisolated(unsafe) usage patterns
rg "nonisolated\(unsafe\) static var"

Length of output: 385


Script:

#!/bin/bash
# Let's check the context of both nonisolated(unsafe) usages and other PreferenceKey implementations

# Check MockProtocol.swift context
rg -B 5 -A 5 "nonisolated\(unsafe\) static var responses" 

# Find all PreferenceKey implementations and their defaultValue
ast-grep --pattern 'struct $NAME: PreferenceKey {
  $$$
  static var defaultValue: $TYPE = $VALUE
  $$$
}'

Length of output: 1557

wxm-ios/DataLayer/DataLayer/Networking/Mock/MockProtocol.swift (1)

20-20: ⚠️ Potential issue

Add proper synchronization for shared dictionary

The nonisolated(unsafe) modifier correctly indicates thread-safety concerns, but the static responses dictionary needs proper synchronization as it's accessed from multiple threads.

Consider implementing one of these solutions:

-    nonisolated(unsafe) static var responses: [String: String] = [:]
+    private static let responsesQueue = DispatchQueue(label: "com.weatherxm.mockprotocol.responses")
+    private static var _responses: [String: String] = [:]
+    
+    nonisolated static var responses: [String: String] {
+        get {
+            responsesQueue.sync { _responses }
+        }
+        set {
+            responsesQueue.sync { _responses = newValue }
+        }
+    }

Or using actor for Swift concurrency:

-    nonisolated(unsafe) static var responses: [String: String] = [:]
+    private static let responsesActor = ResponsesActor()
+    
+    private actor ResponsesActor {
+        var responses: [String: String] = [:]
+        
+        func get() -> [String: String] {
+            responses
+        }
+        
+        func set(_ newValue: [String: String]) {
+            responses = newValue
+        }
+    }
+    
+    static var responses: [String: String] {
+        get async {
+            await responsesActor.get()
+        }
+        set {
+            Task {
+                await responsesActor.set(newValue)
+            }
+        }
+    }

Committable suggestion skipped: line range outside the PR's diff.

station-widget/StationTimelineEntry.swift (1)

10-10: 💡 Codebase verification

Several DomainLayer imports need @preconcurrency attribute

The verification revealed inconsistent usage of @preconcurrency attribute across the codebase. Many files importing DomainLayer lack the required attribute for Swift 6 compatibility:

  • Most files in wxm-ios/DataLayer/ need the attribute
  • All files in PresentationLayer/ need the attribute
  • Only a few files like station-widget/* and some repository implementations correctly use @preconcurrency
🔗 Analysis chain

LGTM! Verify other DomainLayer imports.

The @preconcurrency attribute is correctly applied to handle potential data races when importing DomainLayer.

Let's verify consistent usage across the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent usage of @preconcurrency with DomainLayer imports
# Expect: All DomainLayer imports should use @preconcurrency

# Search for DomainLayer imports without @preconcurrency
echo "=== Checking for non-preconcurrency DomainLayer imports ==="
rg "^import\s+DomainLayer\s*$" --type swift

# Search for DomainLayer imports with @preconcurrency
echo -e "\n=== Checking for preconcurrency DomainLayer imports ==="
rg "^@preconcurrency\s+import\s+DomainLayer\s*$" --type swift

Length of output: 17999

wxm-ios/DataLayer/DataLayer/Networking/Interceptors/AuthInterceptor.swift (1)

14-14: ⚠️ Potential issue

Critical: Unsafe concurrent access to mutable state

Using @unchecked Sendable bypasses important thread-safety checks, which is risky for this class because:

  1. It contains mutable state (cancellableSet)
  2. It handles sensitive data (authentication tokens)
  3. It performs network operations

Consider these safer alternatives:

  1. Make the class thread-safe by wrapping mutable state in an actor:
private actor CancellableStorage {
    var cancellables: Set<AnyCancellable> = []
    
    func store(_ cancellable: AnyCancellable) {
        cancellables.insert(cancellable)
    }
}
  1. Or implement proper Sendable conformance by synchronizing access to shared state:
private let queue = DispatchQueue(label: "com.weatherxm.authinterceptor")
private var _cancellableSet: Set<AnyCancellable> = []

private func storeCancellable(_ cancellable: AnyCancellable) {
    queue.sync { _cancellableSet.insert(cancellable) }
}
PresentationLayer/Utils/Weather/WeatherUnitsManager.swift (1)

13-17: ⚠️ Potential issue

Consider safer alternatives to nonisolated(unsafe)

The nonisolated(unsafe) attribute on the singleton property bypasses Swift's actor isolation checks, which could lead to race conditions when accessing shared state (UserDefaults, analytics) from multiple threads. Consider these safer alternatives:

  1. Use an actor to synchronize access:
actor WeatherUnitsManagerActor {
    static let shared = WeatherUnitsManagerActor()
    private let manager: WeatherUnitsManager
    
    private init() {
        let useCase = SwinjectHelper.shared.getContainerForSwinject().resolve(MainUseCase.self)!
        self.manager = WeatherUnitsManager(mainUseCase: useCase)
    }
    
    func getManager() -> WeatherUnitsManager {
        return manager
    }
}
  1. Or use a serial dispatch queue:
static let `default`: WeatherUnitsManager = {
    let queue = DispatchQueue(label: "com.weatherxm.unitsmanager")
    return queue.sync {
        let useCase = SwinjectHelper.shared.getContainerForSwinject().resolve(MainUseCase.self)!
        return WeatherUnitsManager(mainUseCase: useCase)
    }
}()
wxm-ios/Toolkit/Toolkit/FirebaseManager/FirebaseManager.swift (1)

15-15: ⚠️ Potential issue

Fix typo in protocol name FirbaseManagerImplementation

There appears to be a typo in the protocol name. It should be FirebaseManagerImplementation instead of FirbaseManagerImplementation.

- private let firebaseManagerImpl: FirbaseManagerImplementation
+ private let firebaseManagerImpl: FirebaseManagerImplementation

This should be fixed across all usages in the file.

Committable suggestion skipped: line range outside the PR's diff.

wxm-ios/Toolkit/Toolkit/FirebaseManager/RemoteConfigManager.swift (1)

157-157: 💡 Codebase verification

⚠️ Potential issue

Critical: Thread-safety violation confirmed in RemoteConfigManager

The verification confirms critical thread-safety concerns:

  1. The class has 17 @Published properties that must be updated on the main thread per SwiftUI requirements
  2. updateProperties() is called from Firebase callbacks through shouldUpdateCallback
  3. The current implementation removes the main thread dispatch, which can lead to SwiftUI runtime warnings or crashes

The changes must be reverted to maintain thread-safety:

func updateProperties() {
-    shouldUpdateCallback?()
+    DispatchQueue.main.async { [weak self] in
+        guard let self else { return }
+        self.shouldUpdateCallback?()
+    }
}
🔗 Analysis chain

Critical: Potential thread-safety violation in updateProperties

The removal of DispatchQueue.main.async is concerning because:

  1. RemoteConfigManager is an ObservableObject and its @Published properties must be updated on the main thread
  2. This method is called from Firebase callbacks which may execute on background threads
  3. The removal of weak self handling could introduce retain cycles

Consider restoring the previous implementation:

func updateProperties() {
-    shouldUpdateCallback?()
+    DispatchQueue.main.async { [weak self] in
+        guard let self else { return }
+        self.shouldUpdateCallback?()
+    }
}

Let's verify where this callback is used:


Let me gather more context about the class and its properties to verify the thread-safety concerns.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for shouldUpdateCallback usage
rg -A 5 "shouldUpdateCallback.*="

Length of output: 617


Script:

#!/bin/bash
# Search for RemoteConfigManager class definition and properties
ast-grep --pattern 'class RemoteConfigManager: ObservableObject {
  $$$
}'

# Search for @Published properties
rg "@Published.*var" wxm-ios/Toolkit/Toolkit/FirebaseManager/RemoteConfigManager.swift

# Search for where updateProperties is called
rg -A 3 "updateProperties\(\)"

Length of output: 2362

wxm-ios/Swinject/SwinjectHelper.swift (1)

8-9: 💡 Codebase verification

Inconsistent usage of @preconcurrency attribute across imports

The verification reveals inconsistent usage of the @preconcurrency attribute across the codebase:

  • DataLayer: Only 1 out of 3 imports uses @preconcurrency
  • DomainLayer: Only 19 out of 100+ imports use @preconcurrency
  • Swinject: Only 1 out of 2 imports uses @preconcurrency

This inconsistency could lead to potential concurrency issues in Swift 6. The attribute should be consistently applied across all imports of these modules to ensure proper backward compatibility during the Swift 6 migration.

🔗 Analysis chain

LGTM! Appropriate use of @preconcurrency attribute.

The addition of @preconcurrency to these imports is correct for the Swift 6 upgrade, as it helps maintain backward compatibility while adopting Swift's new concurrency model.

Let's verify consistent usage across the codebase:

Also applies to: 11-11

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent usage of @preconcurrency with these imports
# Expected: All imports of these modules should use @preconcurrency

echo "Checking DataLayer imports..."
rg "^import DataLayer" --type swift
rg "^@preconcurrency import DataLayer" --type swift

echo "Checking DomainLayer imports..."
rg "^import DomainLayer" --type swift
rg "^@preconcurrency import DomainLayer" --type swift

echo "Checking Swinject imports..."
rg "^import Swinject" --type swift
rg "^@preconcurrency import Swinject" --type swift

Length of output: 18487

wxm-ios/Toolkit/Toolkit.xcodeproj/project.pbxproj (1)

264-264: 💡 Codebase verification

Deployment target inconsistencies detected across modules

The project upgrade to Xcode 16.1.0 (build 1610) has revealed inconsistent deployment targets across different modules:

  • Main app targets iOS 14.0-17.0 in different configurations
  • Toolkit module targets iOS 15.0-16.2
  • DataLayer, DomainLayer, and PresentationLayer modules target iOS 14.0-15.0

These inconsistencies could lead to runtime issues. Consider:

  • Aligning deployment targets across all modules
  • Setting a consistent minimum iOS version based on your app's requirements
  • Updating any deprecated APIs if targeting newer iOS versions
🔗 Analysis chain

Project settings updated to latest Xcode version.

The LastUpgradeCheck has been updated from 1530 to 1610, indicating a project-wide upgrade to support the latest Xcode features and improvements.

Let's verify the minimum deployment target compatibility:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check deployment target settings
rg "IPHONEOS_DEPLOYMENT_TARGET" 

Length of output: 3672

wxm-ios/DataLayer/DataLayer.xcodeproj/project.pbxproj (1)

722-723: 💡 Codebase verification

⚠️ Inconsistent Swift version configuration across modules

The verification reveals inconsistencies in Swift version settings across the project modules:

  • DataLayer: Swift 6.0 ✓
  • Toolkit: Swift 6.0 ✓
  • DomainLayer: Still on Swift 5.0 ⚠️
  • PresentationLayer: Still on Swift 5.0 ⚠️
  • Main project (wxm-ios): Mixed Swift 5.0 and 6.0 settings ⚠️

While strict concurrency checking is properly configured where Swift 6.0 is used, the inconsistent Swift versions across modules could lead to compatibility issues. All modules should be upgraded to Swift 6.0 to maintain consistency and ensure proper concurrency checking throughout the codebase.

🔗 Analysis chain

Swift 6 upgrade with strict concurrency checking

The changes appropriately configure Swift 6 and enable complete concurrency checking across all build configurations (Mock, Debug, Release). This is a good practice as it:

  1. Ensures consistent behavior across all configurations
  2. Helps catch potential concurrency issues at compile time
  3. Aligns with modern Swift concurrency best practices

Let's verify the Swift version requirements are consistent across the codebase:

Also applies to: 881-882, 917-918

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check Swift version settings across all xcodeproj files
# Expected: Should find SWIFT_VERSION = 6.0 consistently

# Search for Swift version settings
rg "SWIFT_VERSION = " --type xml

Length of output: 183


Script:

#!/bin/bash
# Let's try a different approach to find Swift version settings in project files
# First, let's find all xcodeproj files that might contain the configuration
fd "project.pbxproj" 

# Then search for Swift version settings without type filter
rg "SWIFT_VERSION = " $(fd "project.pbxproj")

# Also search for strict concurrency settings
rg "SWIFT_STRICT_CONCURRENCY = " $(fd "project.pbxproj")

Length of output: 3728

wxm-ios/DataLayer/DataLayer/Networking/Interceptors/RequestHeadersAdapter.swift (1)

37-38: ⚠️ Potential issue

Remove unnecessary await on synchronous property access

Properties like UIDevice.current.systemVersion and UIDevice.modelName are synchronous and do not require await. Using await on synchronous properties may cause compiler warnings or unnecessary overhead.

Apply this diff to remove the unnecessary await keywords:

-    		let systemVersion = await UIDevice.current.systemVersion
+    		let systemVersion = UIDevice.current.systemVersion

-    		let deviceInfo = "Device: \(await UIDevice.modelName)"
+    		let deviceInfo = "Device: \(UIDevice.modelName)"

Also applies to: 41-41

wxm-ios/Toolkit/Toolkit/FirebaseManager/NotificationsHandler.swift (1)

22-22: ⚠️ Potential issue

Review the use of nonisolated(unsafe) for cancellableSet

The attribute nonisolated(unsafe) bypasses concurrency safety checks, which may lead to data races. It's crucial to confirm that accessing cancellableSet from concurrent contexts is thread-safe. Consider using concurrency-safe constructs like actors or locks to manage this mutable state.

wxm-ios/DataLayer/DataLayer/RepositoryImplementations/DeviceInfoRepositoryImpl.swift (1)

45-53: 🛠️ Refactor suggestion

Handle potential nil self when using [weak self] in Task closure

In the rebootStation method, the Task closure captures self weakly and uses self? when accessing bluetoothWrapper. If self becomes nil, the asynchronous operations will be skipped, and no further state will be emitted to valueSubject, potentially leaving subscribers waiting indefinitely. Consider handling the nil case explicitly by sending an appropriate error state to valueSubject to prevent indefinite waiting.

Apply the following change to ensure proper handling:

 Task { @MainActor [weak self, valueSubject] in
     valueSubject.send(.connect)
+    guard let self = self else {
+        valueSubject.send(.failed(.unknown))
+        return
+    }
     if let error = await self.bluetoothWrapper.connect(device: device) {
         valueSubject.send(.failed(error.toRebootError))
         return
     }
     valueSubject.send(.rebooting)
     if let error = await self.bluetoothWrapper.reboot(device: device) {
         valueSubject.send(.failed(error.toRebootError))
         return
     }
     valueSubject.send(.finished)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Task { @MainActor [weak self, valueSubject] in
    valueSubject.send(.connect)
    guard let self = self else {
        valueSubject.send(.failed(.unknown))
        return
    }
    if let error = await self.bluetoothWrapper.connect(device: device) {
        valueSubject.send(.failed(error.toRebootError))
        return
    }

    valueSubject.send(.rebooting)
    if let error = await self.bluetoothWrapper.reboot(device: device) {
station-widget/Station_widget.swift (2)

59-59: ⚠️ Potential issue

Avoid using nonisolated(unsafe) to prevent data races

Using nonisolated(unsafe) on station can lead to unsafe concurrent access. It's advisable to find a safer alternative to access configuration.selectedStation without bypassing isolation checks.

Suggested Change:

Access station within the Task to maintain isolation:

- nonisolated(unsafe) let station = configuration.selectedStation
  Task { @MainActor in
+     let station = configuration.selectedStation
      let entry = await getEntry(for: station, displaySize: displaySize)
      let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
      completion(timeline)
  }

Committable suggestion skipped: line range outside the PR's diff.


13-13: 💡 Codebase verification

⚠️ Potential issue

Based on the findings, I can now provide the final response:

@unchecked Sendable usage requires attention for thread safety

The verification reveals potential thread-safety issues:

  • CancellableWrapper contains a mutable Set<AnyCancellable> property but doesn't conform to Sendable
  • WidgetUseCase contains a CancellableWrapper instance and dependencies (meRepository, keychainRepository) but doesn't conform to Sendable
  • Multiple other components in the codebase use CancellableWrapper for managing cancellables, suggesting this is a systemic concern

To ensure thread safety:

  • Make CancellableWrapper thread-safe by using appropriate synchronization and conforming to Sendable
  • Verify that MeRepository and KeychainRepository are Sendable-compliant
  • Consider using @MainActor if the widget only needs to run on the main thread
🔗 Analysis chain

Verify the safety of @unchecked Sendable conformance

Marking Provider as @unchecked Sendable bypasses the compiler's safety checks for concurrency. Ensure that all properties within Provider, such as useCase and cancellableWrapper, are safe to use across concurrency domains or are themselves Sendable.

Consider reviewing the properties for Sendable conformance:

private let useCase: WidgetUseCase
private let cancellableWrapper: CancellableWrapper = .init()

Run the following script to check Sendable conformance of properties:


Let me gather more information about these types to better understand their implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that WidgetUseCase and CancellableWrapper conform to Sendable.

# Check for Sendable conformance in WidgetUseCase
ast-grep --pattern $'struct WidgetUseCase: Sendable { $$$ }' --json

# Check for Sendable conformance in CancellableWrapper
ast-grep --pattern $'final class CancellableWrapper: Sendable { $$$ }' --json

Length of output: 153


Script:

#!/bin/bash
# Check the implementation of WidgetUseCase
ast-grep --pattern 'struct WidgetUseCase {
  $$$
}'

# Check the implementation of CancellableWrapper
ast-grep --pattern 'class CancellableWrapper {
  $$$
}'

# Search for any other references to these types
rg "WidgetUseCase|CancellableWrapper" -A 3

Length of output: 9385

wxm-ios/DataLayer/DataLayer/RepositoryImplementations/Bluetooth/BTActionsWrapper.swift (1)

14-14: ⚠️ Potential issue

BTActionWrapper contains non-Sendable properties but is marked as @unchecked Sendable

Marking BTActionWrapper as @unchecked Sendable asserts that it's safe to share instances across concurrency domains without compiler verification. However, the class contains several non-Sendable properties:

  • cancellables: Set<AnyCancellable>: AnyCancellable does not conform to Sendable.
  • scanningTimeoutWorkItem: DispatchWorkItem?: DispatchWorkItem is a reference type and not Sendable.
  • rebootStationWorkItem: DispatchWorkItem?: Same as above.
  • performCommandDelegate: BTPerformCommandDelegate?: Unless BTPerformCommandDelegate conforms to Sendable, this could be unsafe.
  • bluetoothManager: BluetoothManager: Ensure that BluetoothManager and its properties are Sendable.

Using these non-Sendable types without proper synchronization can lead to data races and undefined behavior. Consider one of the following:

  • Refactor the class to remove or safely handle non-Sendable properties, possibly by enforcing thread confinement or adding synchronization mechanisms.
  • Avoid marking the class as @unchecked Sendable until it can be safely shared across concurrency domains.

Apply this diff to remove the @unchecked Sendable annotation for now:

-class BTActionWrapper: @unchecked Sendable {
+class BTActionWrapper {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

class BTActionWrapper {
wxm-ios/DataLayer/UserDevicesService.swift (2)

19-19: ⚠️ Potential issue

Ensure Thread Safety when using @unchecked Sendable

By declaring UserDevicesService as @unchecked Sendable, you're asserting that it is safe for use across concurrency domains without compiler enforcement. Please ensure that all properties and methods within this class are thread-safe to prevent potential data races or concurrency issues.


184-184: ⚠️ Potential issue

Use .storeThreadSafe instead of .store for thread safety

Replace .store(in: &cancellableSet) with .storeThreadSafe(in: &cancellableSet) to ensure thread-safe access to cancellableSet, consistent with its usage elsewhere in the class.

Apply this diff to fix the issue:

-                    .store(in: &cancellableSet)
+                    .storeThreadSafe(in: &cancellableSet)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

                .storeThreadSafe(in: &cancellableSet)
wxm-ios.xcodeproj/project.pbxproj (1)

3535-3536: 💡 Codebase verification

Swift concurrency safety needs attention - @unchecked Sendable usage detected

Several classes and structs are marked with @unchecked Sendable, which bypasses the compiler's strict concurrency checking. This could lead to data races and thread safety issues. Key locations that need review:

  • Core Services:
    • WXMAnalytics, Logger, FirebaseManager, RemoteConfigManager
  • Data Layer:
    • UserInfoService, UserDevicesService, DeviceInfoRepositoryImpl, FirmwareUpdateImpl
    • Network components: AuthInterceptor, RequestHeadersAdapter, MockProtocol
    • Bluetooth: BTActionWrapper
  • Widget Components:
    • Provider, StationTimelineEntry
  • Domain Models:
    • DeviceDetails

Consider:

  1. Implementing proper thread-safe mechanisms instead of using @unchecked
  2. Ensuring all mutable state is properly synchronized
  3. Using actors or other Swift concurrency features where appropriate
🔗 Analysis chain

Verify the strict concurrency setting across the codebase.

Setting SWIFT_STRICT_CONCURRENCY to complete is a good practice for ensuring safe concurrency. However, please ensure that all the code in the project adheres to this strict setting to avoid any potential runtime issues.

Run the following script to verify strict concurrency adherence:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify strict concurrency adherence across Swift files.

# Test: Search for occurrences of `@unchecked` attributes that bypass strict concurrency checks.
#       Expect: No concerning usages of `@unchecked`.
rg --type swift $'@unchecked\s+(Sendable|MainActor)'

Length of output: 1856

@pantelisss pantelisss changed the base branch from feature/fe-1352-upgrade-swift-version-to-6-for-widget-target to feature/swift_6_upgrade December 2, 2024 07:49
@pantelisss pantelisss merged commit ad5a996 into feature/swift_6_upgrade Dec 2, 2024
2 checks passed
@pantelisss pantelisss deleted the feature/fe-1351-upgrade-swift-version-to-6-for-datalayer-target branch December 2, 2024 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants