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

Swift调用ObservableObject时崩溃,Firebase文件上传无报错

问题:Swift ObservableObject调用时崩溃无报错,Firebase集合/文档创建失败

我正在开发一个Swift的ObservableObject类,每次调用这个对象时程序就崩溃,而且没有任何报错信息。查了Firebase API文档也没找到明确原因。我的需求是调用该对象时,能在Firebase中创建新的集合和文档,相关代码如下:

import Foundation
import FirebaseFirestore
import FirebaseStorage
import FirebaseFirestoreSwift

enum Action {
    case Upload
    case Download
}

enum TransferType {
    case URL(Address: String)
    case Firebase(Collection: String, DocumentID: String)
}

enum ModelType {
    
    //MARK: - #1
    //Different Types of Model Types that will be uploaded and downloaded
    case ActiveJobsite
    case UserData
}

class JsonRequest: ObservableObject {
    
    let db = Firestore.firestore()
    
    @Published var URL: String?
    
    
    //MARK: - #2
    //Temporary optionals for each custom model type
    
    @Published var ActiveJobsite: [ActiveJob]?
    
    @Published var UserData: UsersData?
    
    
    
    //Status of Upload-Download Request
    
    @Published var Completed: Bool = false
    
    @Published var Fetching: Bool = false
    
    @Published var CollectionID: String?
    
    @Published var DocumentID: String?
    
    
    func JsonRequest(TransferType: TransferType, ModelType: ModelType, Action: Action) {
        if Action == .Download {
            DownloadJson()
        } else
        if Action == .Upload {
            UploadJson(ModelType: ModelType, TransferType: TransferType)
        } else {
            //Errpr
        }
        
    }
        
    func DownloadJson(){
        
        
        
  //      db.addDocument(data: <#T##[String : Any]#>)
    }
    
    func UploadJson(ModelType: ModelType, TransferType: TransferType) {
        
        let JsonEncoder = JSONEncoder()
        JsonEncoder.outputFormatting = .prettyPrinted
                // case Firebase
                switch TransferType {
                        
                    case .Firebase(let Collection, let DocumentID):
                    //Test If Document Exsists
//MARK: - #3
//Make a encoder for Each Model Type
                    
                    //ActiveJob Encoder
                        if ModelType == .ActiveJobsite {
                            
                            if let Jobsite = self.ActiveJobsite {
                                do {
                                    let encodedData = try JsonEncoder.encode(Jobsite)
                                    FirebaseUpload(Collection: Collection, DocumentId: DocumentID, Data: encodedData)
                                } catch {
                                    //error
                                }
                            }
                        }
                    
                     //UserData Encoder
                    
                        if ModelType == .UserData {
                            
                            if let UserData = self.UserData {
                                do {
                                    let encodedData = try JsonEncoder.encode(UserData)
                                    FirebaseUpload(Collection: Collection, DocumentId: DocumentID, Data: encodedData)
                                } catch {
                                    //error
                                }
                            }
                        }
                    
                    case .URL(let address):
                        UploadError(Address: address)
                    }

        
        
    }

    func FirebaseUpload(Collection: String, DocumentId: String, Data: Data) {
        //Test If Document Exsists
        let File = db.collection("\(Collection)").document("\(DocumentId)")
            
            do {
                if let json = try JSONSerialization.jsonObject(with: Data, options: []) as? [String : Any] {
                    
                    File.setData(json)
                } else {
                    //Error
                    print("errorMsg")
                }
            } catch {
                print("errorMsg")
            }
        }

    func UploadError(Address: String) {
        print("Cant Upload to URL: \(Address)")
        }
}

崩溃原因排查与修复方案

1. 类名与方法名冲突

你的类名为JsonRequest,但内部定义了同名方法func JsonRequest(...),这会和类的构造逻辑冲突。Swift中与类同名的方法会被识别为构造器,但该方法未遵循构造器规则,调用时直接引发崩溃。

修复:
将方法改名并调整参数命名规范:

func performRequest(transferType: TransferType, modelType: ModelType, action: Action) {
    fetching = true
    completed = false
    
    switch action {
    case .Upload:
        uploadJson(modelType: modelType, transferType: transferType)
    case .Download:
        downloadJson()
    }
}

2. JSON格式不兼容Firestore文档结构

ActiveJobsite是数组类型[ActiveJob],编码后为JSON数组,但Firestore文档要求必须是键值对(字典)结构。直接将数组转[String: Any]会失败,后续逻辑异常引发崩溃。

修复:
上传数组时将其包装进字典,适配Firestore要求:

// 在UploadJson的ActiveJobsite分支中
if let Jobsite = self.ActiveJobsite {
    do {
        // 把数组包装为字典
        let wrappedData = ["jobsites": Jobsite]
        let encodedData = try JsonEncoder.encode(wrappedData)
        FirebaseUpload(Collection: Collection, DocumentId: DocumentID, Data: encodedData)
    } catch {
        print("编码失败:\(error.localizedDescription)")
    }
}

3. 错误处理缺失具体信息

代码中仅用print("errorMsg")处理错误,无法获取具体崩溃原因(比如模型未遵循Codable、Firebase初始化失败等),导致排查无据。

修复:
打印具体错误信息,同时确保模型类遵循Codable协议:

// 编码错误处理
catch {
    print("ActiveJob编码失败:\(error.localizedDescription)")
}

// 模型类示例
struct ActiveJob: Codable {
    // 模型属性
}
struct UsersData: Codable {
    // 模型属性
}

4. Firebase异步操作未处理回调

setData是异步方法,当前代码未处理完成回调,Completed状态更新不及时,可能导致依赖状态的逻辑异常。

修复:
添加闭包回调更新状态:

func FirebaseUpload(Collection: String, DocumentId: String, Data: Data, completion: @escaping (Error?) -> Void) {
    let File = db.collection(Collection).document(DocumentId)
    do {
        if let json = try JSONSerialization.jsonObject(with: Data) as? [String : Any] {
            File.setData(json) { error in
                completion(error)
            }
        } else {
            completion(NSError(domain: "JsonRequest", code: -1, userInfo: [NSLocalizedDescriptionKey: "JSON格式不兼容"]))
        }
    } catch {
        completion(error)
    }
}

调用时更新状态:

FirebaseUpload(Collection: Collection, DocumentId: DocumentID, Data: encodedData) { [weak self] error in
    DispatchQueue.main.async {
        self?.Fetching = false
        self?.Completed = error == nil
        if let error = error {
            print("上传失败:\(error)")
        }
    }
}

5. 命名规范混乱

代码中大小写不统一(如DownloadJson、ActiveJobsite),增加调试难度,建议遵循Swift规范:

  • 类/枚举名:大驼峰(如JsonRequest)
  • 方法/变量名:小驼峰(如downloadJson、activeJobsite)

内容的提问来源于stack exchange,提问作者Thea Young

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 21:56:59