Skip to content

Comments

Replace SelectedTab force unwrap with safe fallback#1052

Merged
aaronbrethorst merged 2 commits intoOneBusAway:mainfrom
diveshpatil9104:fix/selected-tab-force-unwrap-fallback
Feb 22, 2026
Merged

Replace SelectedTab force unwrap with safe fallback#1052
aaronbrethorst merged 2 commits intoOneBusAway:mainfrom
diveshpatil9104:fix/selected-tab-force-unwrap-fallback

Conversation

@diveshpatil9104
Copy link
Contributor

Summary

Replace SelectedTab(rawValue: raw)! with SelectedTab(rawValue: raw) ?? .map on line 667 of UserDataStore.swift.

Problem

SelectedTab(rawValue:) is a failable initializer — it returns nil for any raw value that doesn't match a case. While the guard on line 663 reduces the risk, the force unwrap is still unsafe if:

  • The SelectedTab enum cases are reordered or removed in a future update
  • UserDefaults data is corrupted or manually modified (e.g., via MDM)

Using ?? .map is consistent with the existing fallback on line 664, which already defaults to .map when the key is absent.

Fix

// Before
return SelectedTab(rawValue: raw)!

// After
return SelectedTab(rawValue: raw) ?? .map

Copy link
Member

@aaronbrethorst aaronbrethorst left a comment

Choose a reason for hiding this comment

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

Hey Divesh, thanks for taking the time to make this fix to UserDataStore.lastSelectedView. You're right that force-unwrapping a failable initializer on data coming from UserDefaults is a crash waiting to happen, and your instinct to use nil-coalescing with .map is consistent with how the rest of the codebase handles this (e.g., MKMapType(rawValue:) ?? .mutedStandard in MapRegionManager, RouteType(rawValue:) ?? .unknown in Route, etc.). Nice catch. Before we can merge this, I will need you to make a couple changes:

Important

  1. Add a log message when the fallback is used. The change as written silently discards the invalid raw value, which makes it impossible to diagnose tab preference issues in production. This file already establishes the convention of logging before falling back — see line 557 (Logger.error("Unable to decode recent map items: \(error)")) and line 777 (Logger.error("Unable to decode \(key): \(error)")). Please follow the same pattern here. Something like:

    guard let tab = SelectedTab(rawValue: raw) else {
        Logger.warn("Invalid SelectedTab raw value \(raw) in UserDefaults. Falling back to .map.")
        return .map
    }
    return tab

Fit and Finish

  1. Add a test for the invalid raw value fallback. The existing tests cover the default and the happy path. Please add a test that writes an out-of-range integer directly to UserDefaults and asserts the fallback to .map:

    func test_selectedTabIndex_invalidRawValueFallsBackToMap() {
        userDefaults.set(999, forKey: "UserDataStore.lastSelectedView")
        expect(self.userDefaultsStore.lastSelectedView) == SelectedTab.map
    }

Thanks again, and I look forward to merging this change.

Copy link
Member

@aaronbrethorst aaronbrethorst left a comment

Choose a reason for hiding this comment

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

Hey Divesh — both items from my earlier review are addressed exactly as requested. The guard let with Logger.warn matches the existing error-logging convention in UserDefaultsStore, and the test for the invalid raw value fallback covers the edge case cleanly. This looks good to merge. Thanks for the quick turnaround!

Copy link
Member

@aaronbrethorst aaronbrethorst left a comment

Choose a reason for hiding this comment

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

Hey Divesh — both items from my earlier review are addressed exactly as requested. The guard let with Logger.warn matches the existing error-logging convention in UserDefaultsStore, and the test for the invalid raw value fallback covers the edge case cleanly. This looks good to merge. Thanks for the quick turnaround!

@aaronbrethorst aaronbrethorst merged commit 11cee55 into OneBusAway:main Feb 22, 2026
2 checks passed
@diveshpatil9104 diveshpatil9104 deleted the fix/selected-tab-force-unwrap-fallback branch February 23, 2026 03:09
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