Swift编译超时问题:分段选择器筛选SQLite查询报错求助
解决思路与优化方案
核心问题分析
- 变量作用域错误:你在
switch的每个case里声明了局部的query变量,外部代码根本访问不到这个变量——而且类里定义的var query: NSURLQueryItem完全多余,和SQL查询的query不是同一概念,直接删掉即可。 - 代码冗余导致类型推断压力:每个
case里的查询链式调用几乎完全重复,编译器要同时处理多个复杂的链式表达式,最终导致类型检查超时。
具体优化步骤
1. 清理无效属性
删掉类里的var query: NSURLQueryItem,这个属性和当前SQL查询逻辑无关,只会造成混淆。
2. 提取公共查询逻辑
把所有case里重复的select、order、limit部分抽出来,仅动态修改where条件,大幅减少代码冗余:
// 先定义基础查询,包含所有公共部分 let baseQuery = airports .select(airportId, codeIataAirport, nameAirportName, latitude, longitude) .order(codeIataAirport) .limit(100)
3. 明确变量类型,解决作用域问题
在switch外声明一个明确类型的查询变量,然后在case里仅修改where条件:
// 明确声明类型,帮助编译器快速完成类型推断 var filteredQuery: SQLite.Query = baseQuery switch filterOption { case "IATA": filteredQuery = baseQuery.where(codeIataAirport.like("\(text)%")) case "ICAO": filteredQuery = baseQuery.where(codeICAOAirport.like("\(text)%")) case "Airport Name": filteredQuery = baseQuery.where( codeIataCity.like("%\(text)%") || nameAirportName.like("%\(text)%") ) default: filteredQuery = baseQuery.where( codeIataAirport.like("%\(text)%") || codeICAOAirport.like("%\(text)%") || codeIataCity.like("%\(text)%") || nameAirportName.like("%\(text)%") ) }
4. 拆分复杂初始化逻辑
把map里的Airport初始化逻辑抽成单独的辅助函数,减少单行代码复杂度,降低编译器类型检查压力:
// 辅助函数:从数据库行转换为Airport实例 private func airportFromRow(_ row: Row, airportId: Expression<Int?>, nameAirportName: Expression<String?>, codeIataAirport: Expression<String?>, latitude: Expression<String?>, longitude: Expression<String?>) -> Airport { return Airport( id: row[airportId] ?? .random(in: 11000...12000), name: row[nameAirportName] ?? "N/A", code: row[codeIataAirport] ?? "N/A", lat: row[latitude] ?? "0.0", long: row[longitude] ?? "0.0" ) }
之后在search函数里调用这个辅助函数:
return try db.prepare(filteredQuery).map { row in airportFromRow(row, airportId: airportId, nameAirportName: nameAirportName, codeIataAirport: codeIataAirport, latitude: latitude, longitude: longitude) }
完整修改后的代码片段
import Foundation import SQLite class AirportsDataSource { var db: Connection? var filterOption: String = "IATA" init() { do { guard let fileURL = Bundle.main.url(forResource: "airports", withExtension: "sqlite") else { print("Could not find the airports.sqlite file in the app bundle.") return } db = try Connection(fileURL.path) } catch { print(error) } } func search(_ text: String) -> [Airport] { guard let db = db else { return [] } do { let airports = Table("mytable") let airportId = Expression<Int?>("airportId") let codeIataAirport = Expression<String?>("codeIataAirport") let codeICAOAirport = Expression<String?>("codeICAOAirport") let codeIataCity = Expression<String?>("codeIataCity") let nameAirportName = Expression<String?>("nameAirport") let latitude = Expression<String?>("latitudeAirport") let longitude = Expression<String?>("longitudeAirport") // 提取公共查询部分 let baseQuery = airports .select(airportId, codeIataAirport, nameAirportName, latitude, longitude) .order(codeIataAirport) .limit(100) // 明确类型的查询变量 var filteredQuery: SQLite.Query = baseQuery switch filterOption { case "IATA": filteredQuery = baseQuery.where(codeIataAirport.like("\(text)%")) case "ICAO": filteredQuery = baseQuery.where(codeICAOAirport.like("\(text)%")) case "Airport Name": filteredQuery = baseQuery.where( codeIataCity.like("%\(text)%") || nameAirportName.like("%\(text)%") ) default: filteredQuery = baseQuery.where( codeIataAirport.like("%\(text)%") || codeICAOAirport.like("%\(text)%") || codeIataCity.like("%\(text)%") || nameAirportName.like("%\(text)%") ) } // 调用辅助函数初始化Airport return try db.prepare(filteredQuery).map { row in airportFromRow(row, airportId: airportId, nameAirportName: nameAirportName, codeIataAirport: codeIataAirport, latitude: latitude, longitude: longitude) } } catch { print("error reading table", error) return [] } } // 辅助函数:从数据库行转换为Airport实例 private func airportFromRow(_ row: Row, airportId: Expression<Int?>, nameAirportName: Expression<String?>, codeIataAirport: Expression<String?>, latitude: Expression<String?>, longitude: Expression<String?>) -> Airport { return Airport( id: row[airportId] ?? .random(in: 11000...12000), name: row[nameAirportName] ?? "N/A", code: row[codeIataAirport] ?? "N/A", lat: row[latitude] ?? "0.0", long: row[longitude] ?? "0.0" ) } } struct Airport: Equatable { let id: Int let name: String let code: String let lat: String let long: String }
额外优化建议
把filterOption改成枚举类型,避免字符串硬编码,减少出错概率:
enum FilterOption: String { case iata = "IATA" case icao = "ICAO" case airportName = "Airport Name" case all } // 类里的属性改成: var filterOption: FilterOption = .iata
之后switch直接使用枚举值,代码更安全易维护。
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

