Skip to content

Commit ae3f972

Browse files
committed
Show error from loadImage(at:) in ImageClassPicker
1 parent 5789cca commit ae3f972

File tree

3 files changed

+56
-13
lines changed

3 files changed

+56
-13
lines changed

HeaderViewer/ImageClassPicker.swift

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct ImageClassPicker: View {
1212
let namedNode: NamedNode
1313
@Binding private var selection: RuntimeObjectType?
1414
@State private var searchString: String = ""
15+
@State private var loadError: Error?
1516

1617
@EnvironmentObject private var listings: RuntimeListings
1718

@@ -32,15 +33,27 @@ struct ImageClassPicker: View {
3233

3334
var body: some View {
3435
Group {
35-
if listings.isImageLoaded(path: namedNode.path) {
36+
if let loadError {
37+
if let dlOpenError = loadError as? DlOpenError,
38+
let errorMessage = dlOpenError.message {
39+
StatusView {
40+
Text(errorMessage)
41+
.font(.callout.monospaced())
42+
.padding(.top)
43+
}
44+
} else {
45+
StatusView {
46+
Text("An unknown error occured trying to load '\(namedNode.path)'")
47+
.padding(.top)
48+
}
49+
}
50+
} else if listings.isImageLoaded(path: namedNode.path) {
3651
let runtimeObjects = self.runtimeObjects
3752
if runtimeObjects.isEmpty {
38-
VStack {
53+
StatusView {
3954
Text("\(namedNode.name) is loaded however does not appear to contain any classes")
4055
.padding(.top)
41-
Spacer()
4256
}
43-
.scenePadding()
4457
} else {
4558
ListView(runtimeObjects, selection: $selection) { runtimeObject in
4659
RuntimeObjectRow(type: runtimeObject)
@@ -49,20 +62,41 @@ struct ImageClassPicker: View {
4962
.searchable(text: $searchString)
5063
}
5164
} else {
52-
VStack {
65+
StatusView {
5366
Text("\(namedNode.name) is not yet loaded")
5467
.padding(.top)
5568
Button {
56-
CDUtilities.loadImage(at: namedNode.path)
69+
do {
70+
try CDUtilities.loadImage(at: namedNode.path)
71+
} catch {
72+
loadError = error
73+
}
5774
} label: {
5875
Text("Load now")
5976
}
6077
.buttonStyle(.bordered)
61-
Spacer()
6278
}
63-
.scenePadding()
6479
}
6580
}
6681
.navigationTitle(namedNode.name)
6782
}
6883
}
84+
85+
private struct StatusView<T: View>: View {
86+
let contents: () -> T
87+
88+
init(@ViewBuilder contents: @escaping () -> T) {
89+
self.contents = contents
90+
}
91+
92+
var body: some View {
93+
ScrollView(.vertical) {
94+
VStack {
95+
contents()
96+
Spacer()
97+
}
98+
}
99+
.frame(maxHeight: .infinity, alignment: .top)
100+
.scenePadding()
101+
}
102+
}

HeaderViewer/NamedNodeView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ struct NamedNodeView: View {
3333
.contextMenu {
3434
if couldLoad(node: child) {
3535
Button {
36-
CDUtilities.loadImage(at: child.path)
36+
try? CDUtilities.loadImage(at: child.path)
3737
} label: {
3838
Label("Load", systemImage: "ellipsis")
3939
}

HeaderViewer/RuntimeListings.swift

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,23 @@ extension CDUtilities {
9898
return rootPath.appending(imagePath)
9999
}
100100

101-
@discardableResult
102-
class func loadImage(at path: String) -> Bool {
103-
path.withCString { cString in
104-
dlopen(cString, RTLD_LAZY) != nil
101+
class func loadImage(at path: String) throws {
102+
try path.withCString { cString in
103+
let handle = dlopen(cString, RTLD_LAZY)
104+
// get the error and copy it into an object we control since the error is shared
105+
let errPtr = dlerror()
106+
let errStr = errPtr.map { String(cString: $0) }
107+
guard handle != nil else {
108+
throw DlOpenError(message: errStr)
109+
}
105110
}
106111
}
107112
}
108113

114+
struct DlOpenError: Error {
115+
let message: String?
116+
}
117+
109118
extension CDUtilities {
110119
class var dyldSharedCacheImageRootNode: NamedNode {
111120
let root = NamedNode("")

0 commit comments

Comments
 (0)