I have a stand alone watchOS app. It works when I deploy the app from XCode to my watch. I have put the app on TestFlight, but the app crashes when it tries to read from a plist file.
The type it is trying to decode is in a swift package. If I move that type from the swift package into my watchOS code base then it works when deployed from TestFlight. But when it is in the swift package it crashes when deployed from TestFlight.
I don't know why this is happening. What is different between using a package between TestFlight and deploying from XCode?
Here is part of the crash report:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x00000000
VM Region Info: 0 is not in any region. Bytes before following region: 3686400
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
UNUSED SPACE AT START
--->
__TEXT 00384000-0039c000 [ 96K] r-x/r-x SM=COW ...Kit Extension
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [384]
Triggered by Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libswiftCore.dylib 0x659e0e06 swift_checkMetadataState + 14
1 libswiftCore.dylib 0x659b66a8 type metadata completion function for ClosedRange<>.Index + 14
2 libswiftCore.dylib 0x659dc504 swift_getGenericMetadata + 1112
3 libswiftCore.dylib 0x659b5644 __swift_instantiateGenericMetadata + 28
4 libswiftFoundation.dylib 0x65b80fb0 PropertyListDecoder.decode<A>+ 651184 (_:from:format:) + 310
5 libswiftFoundation.dylib 0x65b80e72 PropertyListDecoder.decode<A>+ 650866 (_:from:) + 40
6 libswiftFoundation.dylib 0x65bf9b2c dispatch thunk of PropertyListDecoder.decode<A>+ 1145644 (_:from:) + 28
7 ...llHelper WatchKit Extension 0x0038ddb6 specialized load<A>(_:) + 40374 (Data.swift:117)
From the crash report it looks like it is crashing at this line of my code:
return try decoder.decode(T.self, from: data)
Below are the details of my project:
In the watch app code base in the Project -> Swift Packages tab:
I included a link to my git repo. It is a private repo on GitHub. For the version rules I have set it to the master branch.
In the "WatchKit Extension" target I have included my package in the "Frameworks, Libraries and Embedded Content" section.
The Deployment Target is 6.1
Here is the code that uses the PropertyListDecoder from the Data.swift file referenced in the crash report.
func load<T: Decodable>(_ filename: String) -> T {
let data: Data
guard let file = Bundle.main.url(forResource: filename, withExtension: nil) else {
os_log("Couldn't find %@ in main bundle", log: Log.data, type: .error, filename)
fatalError("Couldn't find \(filename) in main bundle.")
}
do {
data = try Data(contentsOf: file)
} catch {
os_log("Couldn't load %@ from main bundle", log: Log.data, type: .error, filename)
fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}
do {
let decoder = PropertyListDecoder()
return try decoder.decode(T.self, from: data) <-- this is the line it crashes at
} catch {
os_log("Couldn't parse %@. Error is: %@", log: Log.data, type: .error, filename, error.localizedDescription)
fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}
Here is the code that is in the swift package manager:
import Foundation
public struct Bar: Hashable, Codable, Identifiable, Comparable {
public var id: Bar{self}
public var name: String
public var weight: Double
public let unit: WeightUnit
public init(name: String, weight: Double, weightUnit: WeightUnit) {
self.name = name
self.weight = weight
self.unit = weightUnit
}
public static func < (lhs: Bar, rhs: Bar) -> Bool {
if lhs.name != rhs.name {
return lhs.name < rhs.name
}else if lhs.weight != rhs.weight {
return lhs.weight < rhs.weight
}else {
return lhs.unit < rhs.unit
}
}
public static func == (lhs: Self, rhs: Self) -> Bool {
return
lhs.name == rhs.name &&
lhs.weight == rhs.weight &&
lhs.unit == rhs.unit
}
}
public enum WeightUnit: String, CaseIterable, Identifiable, Codable, Comparable {
case Kilo = "kg"
case Pound = "lb"
public var id: WeightUnit {self}
public func description() -> String {
switch self {
case .Kilo:
return "Metric (\(self.rawValue))"
case .Pound:
return "Imperial (\(self.rawValue))"
}
}
public static func < (lhs: WeightUnit, rhs: WeightUnit) -> Bool {
lhs.description() < rhs.description()
}
public static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue == rhs.rawValue
}
}
After more research I fixed my problem via this Stackoverflow answer.
In the app code base I changed the Build Settings -> Dead Code Stripping from "yes" to "no" in the Project and all targets.