采用MVVM模式开发时URLSESSION变量不可用问题及相关代码
Hey there! Let's tackle this URLSession variable access issue you're hitting with your MVVM setup. First, let's start by laying out the code you shared clearly, then break down the most common pitfalls and how to fix them.
Your Provided Code
foodModel Class
class foodModel: NSObject { var name :String! var city :String! var imageurl :String! init?(dictionary :JSONDictionary) { guard let name = dictionary["name"] as? String, let imageurl = dictionary["imageurl"] as? String, let city = dictionary["city"] as? String else { return } self.name = name self.city = city self.imageurl = imageurl } }
foodDataSourceModel Class (Partial)
class foodDataSourceModel: NSObject { var dataListArray:Array<foodModel>? = ... }
Common Causes & Fixes
Since you didn't share the full URLSession implementation in foodDataSourceModel, I'll cover the most frequent reasons variables seem "unavailable" in URLSession callbacks with MVVM:
Weak Self & Instance Lifecycle
URLSession tasks run asynchronously. If yourfoodDataSourceModelinstance gets deallocated before the task finishes, the callback won't have access to its variables. Always use[weak self]in the closure to avoid retain cycles, then unwrapselfexplicitly to confirm it still exists:let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let self = self else { print("DataSource model was released before request completed") return } // Now you can safely access self.dataListArray here }Uninitialized Optional Variables
YourdataListArrayis an optional array. If you try to append to it or assign values without initializing it first, it'll stayniland appear "unavailable". Either initialize it as an empty array upfront:var dataListArray: [foodModel] = []Or explicitly create an array when parsing data:
self.dataListArray = jsonArray.compactMap { foodModel(dictionary: $0) }Thread Safety for UI-Bound Variables
URLSession callbacks run on a background thread. If yourdataListArrayfeeds into a ViewModel that updates the UI, you need to dispatch any variable updates to the main thread to ensure they're accessible to the UI layer:DispatchQueue.main.async { self.dataListArray = parsedModels // Notify ViewModel of update (via closure/delegate) self.onDataLoaded?() }
Example Complete foodDataSourceModel Implementation
Here's a polished version of your data source model that addresses all these issues:
class foodDataSourceModel: NSObject { var dataListArray: [foodModel]? // Closure to notify ViewModel when data is ready var onDataFetched: (() -> Void)? func fetchFoodData(from urlString: String) { guard let url = URL(string: urlString) else { return } let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let self = self else { return } if let error = error { print("Fetch error: \(error.localizedDescription)") return } guard let data = data else { print("No data received from request") return } do { if let jsonArray = try JSONSerialization.jsonObject(with: data) as? [JSONDictionary] { self.dataListArray = jsonArray.compactMap { foodModel(dictionary: $0) } // Update on main thread for UI compatibility DispatchQueue.main.async { self.onDataFetched?() } } } catch { print("JSON parsing error: \(error.localizedDescription)") } } task.resume() } }
内容的提问来源于stack exchange,提问作者simon

