💡 开发笔记

记录开发过程中的技术发现、问题解决方案和经验总结

🔒 Swift 6 中让 Any 类型遵循 Sendable 协议

问题背景

在 Swift 6 的严格并发检查模式下,Any 类型默认不遵循 Sendable 协议,会导致编译警告或错误:

⚠️ Type 'Any' does not conform to protocol 'Sendable'

解决方案

使用 any Any & Sendable 来明确声明类型既可以是任意类型,又遵循 Sendable 协议:

// ❌ Swift 6 下会报错
var data: Any
func processData(_ input: Any) { }

// ✅ 正确写法
var data: any Any & Sendable
func processData(_ input: any Any & Sendable) { }

使用场景

  • 属性声明var value: any Any & Sendable
  • 函数参数func handle(_ data: any Any & Sendable)
  • 闭包捕获let callback: (any Any & Sendable) -> Void
  • 泛型约束struct Container
💡 语法说明:
  • any 关键字表示存在类型(existential type)
  • Any & Sendable 表示类型必须同时满足 Any 和 Sendable
  • 组合写法:any ProtocolA & ProtocolB
⚠️ 注意:
  • Swift 6 默认启用严格并发检查
  • 如果确定类型是线程安全的,可以使用 @unchecked Sendable 绕过检查
  • 但对于 Any 类型,推荐使用 any Any & Sendable 明确约束
✅ 完整示例:
class DataManager: @unchecked Sendable {
    // 存储任意 Sendable 类型的数据
    var cache: [String: any Any & Sendable] = [:]
    
    // 接收 Sendable 参数
    func store(_ value: any Any & Sendable, forKey key: String) {
        cache[key] = value
    }
    
    // 返回 Sendable 类型
    func retrieve(forKey key: String) -> (any Any & Sendable)? {
        return cache[key]
    }
}
📦 iOS Framework OC/Swift 混编 + CocoaPods 依赖头文件问题

问题场景

当你开发一个本地 Framework,并且:

  • Framework 是 OC/Swift 混编 项目
  • Framework 通过 podpodspecdependency 引入一个 OC 第三方库
  • 未来这个 Framework 要通过 pod install 接入到主项目

问题描述

pod install 后,在 Framework 工程中找不到 OC 第三方库的头文件,编译报错。

根本原因

CocoaPods 自动生成的 umbrella header(如 FrameworkName-umbrella.h不会自动添加对 pod 依赖的 OC 库的头文件引用。这意味着:

  • Swift 代码无法直接看到 OC 第三方库的类
  • 即使你在 Bridging Header 中声明,也找不到 OC 类的定义

解决方案

在 Framework 项目中创建一个专门的聚合头文件,手动引用需要用到的 OC 第三方库头文件:

// FrameworkName.h(文件名任意,建议与 Framework 同名)

#import <Foundation/Foundation.h>

// ⚠️ 关键:手动导入 OC 第三方库的头文件
#import <AFNetworking/AFNetworking.h>
#import <SDWebImage/SDWebImage.h>
// 或其他你依赖的 OC 库

// 如果有需要导出的 OC 类,也在这里导入
#import <FrameworkName/YourOCClass.h>

配置步骤

  1. 创建聚合头文件

    在 Framework 项目中创建一个头文件(如 FrameworkName.h),把所有需要用到的 OC 第三方库头文件都 import 一遍。

  2. 确保头文件被编译

    将这个头文件添加到 Framework 的 Target 中(默认会自动添加)。

  3. 在 Swift 代码中使用
    import FrameworkName
    
    // 现在可以使用 OC 第三方库的类了
    let manager = AFHTTPSessionManager()
    let image = SDImageCache.shared().imageFromDiskCache(forKey: "key")
✅ 实际验证:

podspec 中配置 spec.public_header_files = "*.h"(通配符公开所有头文件),不需要显式指定 s.umbrella_header,只要创建了聚合头文件并 import 了 OC 依赖,pod install 后就能正常使用。

💡 推荐配置:
# podspec 中
spec.public_header_files = "*.h"  # 公开所有头文件(通配符)
# spec.umbrella_header 不需要显式指定,CocoaPods 会自动处理

使用通配符 "*.h" 可以让 CocoaPods 自动找到你的聚合头文件并将其作为 umbrella header 使用。

⚠️ 关键注意:
  • 核心是创建聚合头文件并手动 import OC 依赖
  • public_header_files = "*.h" 会公开所有头文件,适合大多数场景
  • 如果想更精细控制,可以指定具体文件,如 'FrameworkName/FrameworkName.h'
  • 所有需要在 Swift 中使用的 OC 第三方库,都必须在这个头文件中导入
✅ 验证方法: pod install 后,在 Framework 的 DerivedData 中检查生成的 umbrella header,确认你的 OC 依赖头文件被正确导入。
🖼️ SwiftUI 图片组件 ScaleToFill 宽度失控问题

问题描述

在 SwiftUI 开发中,当图片组件设置为 ScaleToFill 时,图片会根据其原始加载大小来渲染,导致:

  • 图片组件自身的宽度不受控制
  • 父组件的宽度也会随之失控,破坏整体布局

解决方案

必须给图片组件显式设置一个固定宽度:

Image("yourImage")
    .resizable()
    .scaledToFill()
    .frame(width: 200)  // ⚠️ 必须设置宽度
💡 小贴士: 如果希望图片自适应父容器宽度,可以使用 .frame(maxWidth: .infinity) 或设置具体的宽度约束。
⚠️ 注意: 不要忘记设置宽度,否则可能导致布局错乱,尤其是在 ScrollView 或 VStack/HStack 中。