You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

适配iOS14使用@FocusState报存储属性不可用错误的解决方法

问题说明

开发最低支持iOS 14的SwiftUI应用时,若尝试直接对存储属性(包括带属性包装器的存储属性)添加@available(iOS 15, *)标记以使用@FocusState这类仅高版本系统支持的属性包装器,会触发Stored properties cannot be marked potentially unavailable编译错误。
该写法在Xcode 13中可编译通过属于旧版本编译器的检查漏洞,Xcode 14补全了存储属性的可用性校验逻辑后会正常报错。计算属性无法附加属性包装器,整份复制View代码会产生大量冗余。
触发报错的示例代码:

struct MyView: View {
  enum Field: Hashable {
    case username
  }

  @State private var myText: String = ""

  @available(iOS 15, *)
  @FocusState private var focusedField: Field?

  var body: some View {
    if #available(iOS 15, *) {
      TextEditor(text: $myText)
        .focused($focusedField, equals: .username)
    } else {
      TextEditor(text: $myText)
    }
  }
}
推荐方案

无需复制整份View代码,将高版本独有的逻辑拆分为被@available标记的独立子组件即可,从根源规避存储属性的版本限制问题:

struct MyView: View {
  enum Field: Hashable {
    case username
  }
  @State private var myText: String = ""

  var body: some View {
    if #available(iOS 15, *) {
      FocusableTextEditor(
        text: $myText,
        targetFocusField: .username
      )
    } else {
      TextEditor(text: $myText)
    }
  }
}

@available(iOS 15, *)
private struct FocusableTextEditor: View {
  @Binding var text: String
  let targetFocusField: Field
  @FocusState private var focusedField: Field?

  var body: some View {
    TextEditor(text: $text)
      .focused($focusedField, equals: targetFocusField)
  }
}

该方案的优势:

  • 无冗余重复代码,版本差异逻辑完全收敛在轻量子组件中
  • 完全符合Swift语法规则,内存布局安全,不存在兼容性崩溃风险
  • 后续扩展高版本独有逻辑时,仅需修改对应子组件,不会污染低版本兼容代码
不推荐的方案
  • 不要尝试通过runtime强转、指针操作绕过编译器检查,这类写法会破坏结构体内存布局,在不同系统版本上极易出现随机崩溃
  • 不建议用ObservableObject包装FocusState实现版本兼容,该方案代码冗余度更高,可读性远差于子组件拆分方案
  • 不建议整份复制主View代码做版本分支,后续维护时需要同步修改两份代码,极易出现逻辑不一致问题

内容的提问来源于stack exchange,提问作者Allan Spreys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:30:49