Swift 4中存储大型字典触发编译错误的技术问询
解决Swift超大字典字面量导致的"Illegal instruction: 4"编译错误
我之前做iOS项目时也碰到过一模一样的问题——当你在Swift里写一个包含几百个键值对的超大字面量字典时,编译器在静态解析这个巨量代码的时候会过载,直接抛出这种看起来摸不着头脑的Illegal instruction: 4错误,和你说的tile编号到106左右报错完全吻合,不是你的逻辑有问题,是编译器扛不住这么大的字面量解析压力。
给你几个靠谱的解决方案,按推荐程度排序:
方案1:用闭包延迟初始化字典(最方便,代码内解决)
把硬编码的字面量字典改成用闭包动态构建,编译器不会一次性解析所有数组字面量,而是在运行时逐步构建字典,完美避开编译期的解析瓶颈。而且如果你的很多tile数组是重复的,还能减少代码冗余:
import Foundation struct TileStore { // 用静态闭包延迟初始化字典 static let tiles: [Int: [Int]] = { var tileDictionary = [Int: [Int]]() // 先批量填充通用的数组(根据你的需求调整) for tileID in 0...175 { // 这里替换成对应tileID的数组,如果有特殊的tile,后面单独覆盖 let defaultArray = [0,11,52,35,54,55,64,70,80,67,54,60,73,162,171,160] tileDictionary[tileID] = defaultArray } // 对有特殊数据的tile单独赋值(比如tile 106如果有不同数组) // tileDictionary[106] = [你的特殊数字数组] // tileDictionary[120] = [另一个特殊数组] return tileDictionary }() }
使用的时候直接调用TileStore.tiles就行,和你之前的用法完全一致,但编译器不会再报错了。
方案2:把数据移到plist文件(数据与代码分离,更易维护)
如果你的tile数据以后可能需要修改,或者数组数量还会增加,把数据放到plist文件里是更好的选择,彻底让编译器摆脱解析超大字面量的负担:
- 在Xcode里新建一个Property List文件(命名为
TileData.plist),设置根类型为Dictionary,键类型选Number(对应Swift的Int),值类型选Array of Number(对应Swift的[Int])。 - 把你字典里的所有键值对复制到plist中(可以用文本编辑器批量转换格式,或者直接在Xcode的plist编辑器里逐个添加,批量添加的话可以把Swift字典转成XML格式粘贴进去)。
- 在Swift里读取这个plist文件:
import Foundation enum TileLoader { static func loadTiles() -> [Int: [Int]] { guard let plistURL = Bundle.main.url(forResource: "TileData", withExtension: "plist"), let plistData = try? Data(contentsOf: plistURL), let tilesDict = try? PropertyListSerialization.propertyList(from: plistData, format: nil) as? [Int: [Int]] else { // 读取失败时返回空字典,或者根据需求处理错误 return [:] } return tilesDict } } // 初始化使用 let tiles = TileLoader.loadTiles()
这个方案的好处是以后修改tile数据不需要改代码,直接编辑plist就行,也不会再触发编译器的解析错误。
方案3:分段排查语法错误(如果是局部语法问题)
虽然你说前106个tile正常,但也有可能是后面的某个数组写错了(比如少了逗号、括号不匹配),导致编译器解析到那里崩溃。可以把字典拆分成几个部分,逐个注释掉测试,定位出错的地方:
let tiles: [Int: [Int]] = { var tempDict = [Int: [Int]]() // 第一部分:0-50 tempDict[0] = [0,11,52,35,54,55,64,70,80,67,54,60,73,162,171,160] tempDict[1] = [0,11,52,35,54,55,64,70,80,67,54,60,73,162,171,160] // ... 填充到50 // 第二部分:51-100 tempDict[51] = [...], // ... 填充到100 // 第三部分:101-175 // tempDict[101] = [...], // ... 填充到175 return tempDict }()
先只保留前两部分编译,如果正常,再逐步加入第三部分,找到导致报错的具体tile数组,修正语法问题即可。
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

