I’ve been pulling my hair on a weird bug in Xcode 10.2.
I’ve had this swift util method to decode JSON objects using ObjectMapper as I can’t call ObjectMapper from ObjectiveC:
#objc static func mapModel(fromClass: AnyClass, jsonDict: [String : Any]) -> Any? {
guard let mappableClass = fromClass as? Mappable.Type else {
fatalError("class \(fromClass) is not Mappable")
}
return mappableClass.init(JSON: jsonDict)
}
Here's how I call it in ObjectiveC:
FullUser *object = [ModelMapperHelper mapModelFromClass:FullUser.class jsonDict:response.resultData];
I had to use AnyClass because Mappable is not compatible with ObjC.
This code has been working fine until I updated to Xcode 10.2.
The last line in the thread in the debugger is swift_checkMetadataState
It’s still working fine with devices on iOS 12.2 and above but it’s crashing with a EXC_BAD_ACCESS at the init() line on iOS 12.1 and below.
If I use the actual class like FullUser.init(JSON: jsonDict) it's all working fine.
Another interesting thing, if I don't pass FullUser.class from objc but set it in swift like so:
#objc static func mapFullUser(jsonDict: [String : Any]) -> Any {
let fromClass = FullUser.self
let mappableClass = fromClass as Mappable.Type
return mappableClass.init(JSON: jsonDict)!
}
it all works fine.
Does anyone have any idea why it’s crashing on older iOS versions and how I can change that code?
Update 1
By just adding print("swift=\(FullUser.self)") before the init() call it's working fine!
I'm starting to think this is a class loader issue.
Maybe it has to do with the fact that the project has 2 targets.
Update 2
I removed the 2nd target and it's still crashing.
Update 3
It also crashes if I just pass the class name as a string and get the class from NSClassFromString in swift.
Update 4
It doesn't crash if I decode the parent class User which FullUser inherits.
#objc(User)
class User: NSObject, Mappable {
#objc(FullUser)
class FullUser: User {
Update 5
I tried to call a different static function than init and it's not crashing.
Related
Just updated to Xcode 12.0 from the last version of Xcode 11/iOS13 and am getting an error in AppDelegate: Thread 1: "Subclass MPMediaItem must implement -valueForProperty: defined in [MPMediaItem class]."
When the app starts, I MPMediaQuery the library for songs and store them to a #Published variable in an Observable Object like this:
#Published var songs = [MPMediaItem]()
init() {
self.songs = MPMediaQuery.songs().items
}
Later when I want to access a property I do so like this:
Text(self.observableObject.songs[0].title)
I’ve tried changing these to use .value(forProperty: "MPMediaItemPropertyTitle") but it doesn’t feel to be use a string over a property (and Xcode then pops up errors like Failed to produce diagnostic for expression; please file a bug report apple.) AFAIK, I’m not subclassing MPMediaItem anywhere and I’ve tried Googling the error above with no luck.
Anyone know what’s going on?
I'm not sure if this is useful to your situation, but I recently came across a simiar problem.
In my case I needed to change 2 things that triggered this crash:
I was initialising an empty MPMediaItem() as placeholder when no current song was loaded. The crash happened when trying to access a property (e.g. title) on this empty instance. Upon removing the empty MPMediaItem() and implementing a different placeholder approach, the problem went away.
To test music on the simlator I was using a DummyMediaQuery: MPMediaQuery which returned an array of DummyMediaItem: MPMediaItem. In the DummyMediaItem class I did:
final class DummyMediaItem: MPMediaItem {
private let _artist: String
override var artist: String { return _artist }
private let _title: String
override var title: String { return _title }
// and so on...
// fix: crash in iOS 14
override func value(forProperty property: String) -> Any? {
return nil
}
}
I have a class to send events defined as follows:
import UIKit
#objc(NativeEventSender)
class NativeEventSender: RCTEventEmitter {
override func supportedEvents() .. {
return ["Supported Event"]
}
#objc func sendEventToJS(_ titleString: String) {
self.sendEvent(withName: "Event", body: titleString)
}
}
This class is exposed to Objective-C using RCT_EXTERN_MODULE() and RCT_EXTERN_METHOD for the sendEventToJS method.
The sendEventToJS method is called in my ViewController.swift. This ViewController is exposed to React-Native through a UIView that is returned by a view manager.
Now every time the sendEventToJS function is fired, the app crashes because the Bridge is nil, with a message saying it wasn't set. The view otherwise renders properly. I have already tried converting the Obj-C example in the documentation to Swift. Tried everything from the sending event issue on the react-native repository and it still doesn't work. Have also tried a few examples on Github where the sendEvent(withName, body) method was used. Any help is greatly appreciated!
I am trying to store a list of subscribers that are ThemeListeners (mostly UIViews or UIViewControllers) and I need these to be stored weakly, otherwise the UIViewControllers are never released and I get memory leaks.
I took the WeakRef class from
https://marcosantadev.com/swift-arrays-holding-elements-weak-references/
When I put this into my project and try and compile it I get an error on the last line in Xcode 9.3:
'WeakRef' requires that 'ThemeListener' be a class type
Compiling this in Xcode 9.2 works.
class WeakRef<T> where T:AnyObject
{
private(set) weak var value : T?
init( value:T?)
{
self.value = value
}
}
protocol ThemeListener : AnyObject
{
}
typealias WeakRefThemeListener = WeakRef<ThemeListener>
Does anyone have any suggestions on how to fix this. I also have the same problem when trying to use NSHashTable.
I think your protocol should be like this:
protocol ThemeListener : class
{}
I found a memory leak in Swift. It gave me nightmares because my code was full of small leaks everywhere, and then I managed to reduce it to this small example,
import UIKit
enum LeakingEnum {
case
LeakCase,
AnotherLeakCase
}
class Primitive {
var lightingType: LeakingEnum = .LeakCase
var mysub : [Int] = []
init() {
mysub.append(80)
}
}
class ViewController: UIViewController {
var prim: Primitive?
override func viewDidLoad() {
super.viewDidLoad()
prim = Primitive()
}
}
If you run this program on an iPhone and Profile with Instruments, you'll find this leak in Array._copyToNewBuffer,
If I remove the call to mysub.append, it stops leaking. If I remove the enum from Primitive, it stops leaking as well. All the classes where I have an enum leak like this. What's going on with Swift enums?
Reproduced in Swift 3, Xcode 8.2.1, and iOS 10.2, on both an iPhone6 and an iPad Pro. Can't reproduce in the Simulator, or in a device with iOS 9.3.2.
You can download a minimal sample app here: https://github.com/endavid/SwiftLeaks
Is this a known bug? Is there any work around?
Edit:
Because this remind me of another enum bug, Accessor gives the wrong value in Swift 1.2/2.0 Release build only, I tried making the enum an #objc Int enum, but it still leaks. However, making lightingType directly an Int does fix the leak...
Edit2:
After updating my iPhone to 10.3 and Xcode to 8.3, the leak is gone. It seems it was an issue of iOS 10.2...
Hey #endavid managed to replicate the issue consistently. We spend a good time trying to figure out what was going on and your post helped a lot!
Here is the sample repo: https://github.com/Giphy/ios-memory-leak-sample
Radar: https://openradar.appspot.com/radar?id=4992108083544064
We are developing SDKs and same exact issue surfaced with a small difference. Since we wanted things to interop we added #objc to the enum definition and things started to leak exactly the way you described given your class has two properties, one enum and one mutable array.
Consistently reproduced the leak:
// Without #objc this enum won't leak
// however when this enum is included in a class
// which contains an array, it will leak
#objc enum leakingObjCMarkedEnum: Int {
// Just some random cases.
case apple, orange
}
// Wrapper class which contains an enum and Array
// The class needs to contain the the Array in order for
// the Enum to leak.
class WrapperClass {
// Optional enums marked with #objc will leak.
var leakyOptionalEnum: leakingObjCMarkedEnum?
// Include an array to trigger this behaviour.
// Empty arrays won't cause the leak, so lets add an arbitrary Int
var myArray: [Int] = [80]
}
class ViewController: UIViewController {
// Hang on to a reference to our Wrapper Class instance.
var wc: WrapperClass?
override func viewDidLoad() {
super.viewDidLoad()
// Allocate an instance of our class
// and things will start leaking at this point.
wc = WrapperClass()
}
}
Work Around:
If we convert the optional enum class property to a non-optional, leak will disappear.
// Let's convert the optional property to a non-optional
var leakyOptionalEnum: leakingObjCMarkedEnum = .orange
Edit:
It is fixed by guys # Apple:
https://bugs.swift.org/browse/SR-5625
PR: https://github.com/apple/swift/pull/11341
I have created a project to test the Typhoon framework , I have created two classes ApplicationAssembly and CoreAssembly where I inject some properties and constructors and a default Configuration.plist to load data from it.
ApplicationAssembly
public class ApplicationAssembly: TyphoonAssembly {
public dynamic func config() -> AnyObject {
return TyphoonDefinition.configDefinitionWithName("Config.plist")
}
}
CoreAssembly
public class CoreAssembly: TyphoonAssembly {
public dynamic func apiHandler() -> AnyObject {
return TyphoonDefinition.withClass(ApiHandler.self) {
(definition) in
definition.useInitializer("initWithDebugging:debugProcess:mainURL:") {
(initializer) in
initializer.injectParameterWith(TyphoonConfig("debug_mode"))
initializer.injectParameterWith(TyphoonConfig("debug_path"))
initializer.injectParameterWith(TyphoonConfig("api_url"))
}
definition.scope = TyphoonScope.Singleton
}
}
public dynamic func viewController() -> AnyObject {
return TyphoonDefinition.withClass(ViewController.self) {
(definition) in
definition.injectProperty("apiHandler", with:self.apiHandler())
}
}
}
I set in my Info.plist the TyphoonInitialAssemblies first the ApplicationAssembly and then the CoreAssembly.
Everything works fine without exceptions or anything except that the app never enters in AppDelegate neither in the ViewController class. I don't know maybe I missed something in the doc or anything.
What I'm missing here?
Why in debug not enter in the ViewController class that is the initial view controller in Storyboard?
The problem was that the ApiHandler class does not extend NSObject, which is a requirement. This is because Typhoon is an introspective Dependency Injection container. As Swift has no native introspection it uses the Objective-C run-time.
The App should not however have crashed in such an obfuscated way. I have opened an issue to look at how to fail with a meaningful error, rather than infinitely recurse.
After solving the initial problem, I also noted that the init method for ApiHandler passing in a Swift Bool object. This needs to be an NSNumber.
init(debugging : NSNumber, debugProcess : String, mainURL : String) {
self.debugging = debugging.boolValue
self.debugProcess = debugProcess
self.mainURL = mainURL
}
Given that Typhoon uses the Objective-C runtime, there are a few quirks to using it with Swift - the same kinds of rules outlined for using Swift with KVO apply.