You can see some example code here:
https://github.com/HearthSim/HSTracker/tree/3.1.1/HSTracker/UIs/Constructed/ActiveEffects
I changed the code recently to try to find where these failures are coming from but it still puzzles me. I have seen some crash reports with memory corruption, so I have a suspicion it may be related to that or some low memory condition.
Post
Replies
Boosts
Views
Activity
@GRALInfo I guarantee that the issue is not with @IBOutlets or wrong Nib name as this would fail every time. I have made that mistake during development and Xcode breaks on those instances.
This is something strange and only affects a very small number of users, mostly on zh_CN locale. I am still perplexed, so short of adding better guard statements to see if I can gleam more information, I don't see anything wrong with the code above.
I was hoping someone had similar experiences and could shed some light.
I understand the advantages of auto layout and I intend to fix several of these issues as I clean up some of the code. But the main issue is that contentView is nil in these crash reports I got and I was just wondering if there was something that could be going wrong with how the NIB is being loaded.
I will be refactoring this common loading code and adding guard statements to provide better fault information in the future. Maybe it is some out of memory issue or corruption that's the culprit as the NIB and connections are all valid, otherwise I would caught it during development and it would crash for a lot more users.
Good to know about objc_enumerateClasses although it could use better documentation. Unfortunately it requires MacOS 13+ and I still have to support 10.14. So far, checking the prefix of the class has been more than sufficient, so I appreciate the help on the issue.
I ended up finding that I needed to exclude any classes not part of the module by doing something like
let name = class_getName(cl)
if memcmp(name, "MyModule.", 9) != 0) {
continue
}
That avoids the Objective-C class initialization problem and it is also much faster. Not perfect but good enough.
If there is a better way to avoid doing this that doesn't involve manually maintaining a list of classes, I can give it a try.
The use case is finding out the list of classes that confirm to a given protocol or are subclasses of a desired class. This avoids having to know the list of classes at compile time and having to maintain the list statically.
Just another side note, I ran into an unexpected issue on the main application code because of NSPreviewTargetController. I was not expecting a cast to cause this threading violation message:
WebKit Threading Violation - initial use of WebKit from a secondary thread.
FAULT: assertion failed: '+[NSRemoteView ensureAuxServiceAwareOfHostApp:] has been invoked on a thread which is incompatible with AppKit; the problem is likely in a much shallower frame in the backtrace' in +[NSRemoteView ensureAuxServiceAwareOfHostApp:] on line 1340 of file /AppleInternal/Library/BuildRoots/4ff29661-3588-11ef-9513-e2437461156c/Library/Caches/com.apple.xbs/Sources/ViewBridge/NSRemoteView.m
Thanks for the feedback and the solution. I have reported the issue via: https://feedbackassistant.apple.com/feedback/15639632
There was not direct choice for Swift runtime, so hopefully that is enough.
Here's a recreate example with swift repl:
import Foundation
protocol DynamicCounter {
init(_ isPlayer: Bool)
}
class BaseCounter: NSObject, DynamicCounter {
required init(_ isPlayer: Bool) {
}
}
class TestCounter: BaseCounter {
required init(_ isPlayer: Bool) {
super.init(isPlayer)
}
}
class Helper {
static func withAllClasses<R>(
_ body: (UnsafeBufferPointer<AnyClass>) throws -> R
) rethrows -> R {
var count: UInt32 = 0
let classListPtr = objc_copyClassList(&count)
defer {
free(UnsafeMutableRawPointer(classListPtr))
}
let classListBuffer = UnsafeBufferPointer(
start: classListPtr, count: Int(count)
)
return try body(classListBuffer)
}
static func initialize() {
let monoClasses = withAllClasses { $0.compactMap { $0 as? BaseCounter.Type } }
for cl in monoClasses {
cl.init(false)
}
}
}
Helper.initialize()
output:
2024-10-29 15:30:48.760664-0400 repl_swift[13210:34621315] *** NSForwarding: warning: object 0x200b5cc48 of class '__NSGenericDeallocHandler' does not implement methodSignatureForSelector: -- trouble ahead
2024-10-29 15:30:48.761418-0400 repl_swift[13210:34621315] *** NSForwarding: warning: object 0x200b5cc48 of class '__NSGenericDeallocHandler' does not implement doesNotRecognizeSelector: -- abort
Execution interrupted. Enter code to recover and continue.
I found a solution by using a little bit of C code:
extern void mono_jit_init (const char *file) attribute((weak_import));
int isMonoAvailable(void)
{
		return mono_jit_init != NULL;
}
and a header for the function as well that is included from the bridging header:
extern int isMonoAvailable(void);
With the above in place, I can call from Swift to check availability:
	if isMonoAvailable() {
		// do something with Mono
	}