Swift accessing app delegate through test cases raises swift_dynamiccast unconditional exception - ios

I am getting swift_dynamiccast unconditional exception while accessing app delegate from test cases in one of the methods in application.
The function in the application is like this:
func sampleMethod()
{
var appdelegate:AppDelegate = UIApplication.sharedApplication().delegate! as AppDelegate
}
Test case is accessing this method as:
func testStart()
{
var sample:MyClass = MyClass()
sample.sampleMethod()
}
It is raising exception in the method sampleMethod(), then it goes ahead. I have added MyClass & AppDelegate files in the test case project in build phases.
Any suggestions whats wrong here? A similar unanswered question here.

This is because AppDelegate object in the case of tests is different type than main project AppDelegate. Because of this your app is crash
class MyClass: NSObject {
func someMethod() {
var checkObject:AnyObject = UIApplication.sharedApplication().delegate!;
NSLog("%#", checkObject.description);
var appdelegate:AppDelegate = AppDelegate();
NSLog("%#", appdelegate);
}
}
You can see result of this function in console:
2015-01-14 13:03:58.299 TestSwift[654:282510] <TestSwift.AppDelegate: 0x17007b940>
2015-01-14 13:04:01.085 TestSwift[654:282510] <TestSwiftTests.AppDelegate: 0x17467f740>
Possible solution: use AnyObject variable instead of casting to AppDelegate

Did you add AppDelegate.swift to the test's target members?
Instead, try importing it from your application module.
And Rick's right. I faced a similar problem, solved it after going through
UIApplication.sharedApplication().delegate as AppDelegate causes EXC_BAD_ACCESS using it on swift unit test

Related

Swift memory leak when iterating array of Errors

I'm relatively new to Swift, so I hope I'm not asking a stupid question.
I have some code that instantiates an array of type Error, which will later be iterated and printed to the console. When running this code through Instruments using the "Leaks" instrument, it shows a leak of _SwiftNativeNSError. If I change the array type from [Error] to [Any], the leak disappears, even though it is still actually holding an object conforming to Error. The leak is not reproducible with any other data types or protocols that I've tried.
Here's some sample code:
class myLeak {
lazy var errors = [Error]()
enum err: Error {
case myFirstError
}
func doSomething() {
errors.append(err.myFirstError)
for error in errors {
print(String(describing: error))
}
}
}
// call with let myleak = myLeak(); myleak.doSomething()
Calling the doSomething() function immediately creates a leak. Switching [Error]() to [Any]() resolves the leak, but I'm not happy with this as a solution without understanding the underlying problem. The problem is also solved by changing [Error]() to my enum implementing the Error protocol: [err](). I've also tried creating my own custom protocol just to prove if this is being caused specifically by Error, and I'm only able to reproduce the problem when using Error; my own custom protocol did not exhibit this behaviour.
Originally, my code used a forEach loop to iterate the array, but I then tried re-writing it to use a standard for loop in case the closure in forEach was causing the issue, but this didn't work.
I'm suspicious that this may be a Swift bug (in which case, I will open an issue for it), but there's also a chance that I'm missing a key piece of understanding. If what I'm doing is bad practice, I'd like to understand why.
Update:
After speaking with Joe Groff, an Apple engineer, this is the bug you could have encountered: https://bugs.swift.org/browse/SR-6536
Original Answer
I've played a bit with your code and I think the problem is due to Error type.
In fact, taking the code by Josh, you can find a different behaviour if you use Error or MyError as the type of your array.
I guess the problem arises since the deinit call is not forwarded to CustomObject since Error is just a protocol and it's not aware of the underlying class. While, MyError is. We can wait for other people to have clarifications on this behaviour.
Just for simplicity, I'm using a Playground here. See that I'm not even trying to print the error value.
import UIKit
class ViewController: UIViewController {
var errors: [Error] = [] // change to MyError to see it working
enum MyError: Error {
case test (CustomObject)
}
class CustomObject {
deinit {
print("deiniting")
}
}
override func viewDidLoad() {
super.viewDidLoad()
let testerror = MyError.test(CustomObject())
errors.append(testerror)
errors.removeAll()
}
}
do {
let viewController = ViewController()
// just for test purposes ;)
viewController.viewDidLoad()
}
I tested your code and it looks like the String(describing) statement is causing the string to retain the error, which is just weird. Here is how I can tell: I created an associated object that prints out when its being deinitialized.
import UIKit
class ViewController: UIViewController {
var errors = [Error]()
override func viewDidLoad() {
super.viewDidLoad()
class CustomObject {
deinit {
print("deiniting")
}
}
enum MyError: Error {
case test (CustomObject)
}
let testerror = MyError.test(CustomObject())
errors.append(testerror)
for error in errors {
//print(String(describing: error))
}
errors.removeAll()
}
}
When the print doesn't run, sure enought he associated object is deinitialized at when the error is removed from the array and the output is:
deiniting
Uncomment the print and the output becomes:
test(CustomObject #1 in stack.ViewController.viewDidLoad() -> ())
At first I thought it was the print that's the problem but If I refactor to:
errors.forEach{print($0)}
I get the output:
test(CustomObject #1 in stack.ViewController.viewDidLoad() -> ())
deiniting
But if I change it to:
errors.map {String(describing:$0)}.forEach{print($0)}
Then deinit is no longer called:
test(CustomObject #1 in stack.ViewController.viewDidLoad() -> ())
Weirdness. Maybe file a radar?
This bug was Fixed in Xcode 9.3.

Crash using failable initializer

I'm getting a strange crash using a failable initializer in Swift. I pretty sure it's a bug in Swift, but figured I do a quick post to see if I'm missing something obvious.
I'm writing an app using CloudKit and added a new convenience initializer to CKRecord:
extension CKRecord {
convenience init?(cloudInfo: NSData?) {
guard let info = cloudInfo else { return nil }
self.init(coder: NSKeyedUnarchiver(forReadingWithData: info))
}
This just uses archived data I created using CKRecord's encodeSystemFieldsWithCode: method to create a CKRecord instance. I used to simply have a method in my class to do this same thing and it worked fine.
When I call this initializer like this:
let record: CKRecord
if let rec = CKRecord(cloudInfo: self.cloudInfo) {
record = rec
} else {
record = CKRecord(recordType: "Item", recordID: CKRecordID(recordName: self.id))
}
When I make that call, I get a crash. It doesn't matter if I pass in nil for cloudInfo or a value. When stepping through the code, the crash seems to happen between returning from the init call and getting back to the caller. For example, if I pass nil and step into the guard statement in the init that seems to work, but as soon as I step off of it, I crash.
I've tried getting rid of guard and going with a simple if let construct, but same outcome. And, I've also just returned nil from the init without any other code, and that also crashes.
I've done the usuals: cleaned the build folder, rebooted, etc.
BTW, by "crash" I mean I'm getting: EXC_BAD_ACCESS (code=1, address=0xfffffffc) at the call site.
Does anyone have any ideas? Maybe it's something obvious that I'm missing.
Thanks.
According to The Swift Programming Language (Swift 2.1) book,
For classes, however, a failable initializer can trigger an initialization failure only after all stored properties introduced by that class have been set to an initial value and any initializer delegation has taken place.
Taken from here.
You can't extend an existing class with stored properties, so the first requirement is met. But to meet the second requirement, you have to delegate your initialization process like in code below:
extension CKRecord {
convenience init?(cloudInfo: NSData?) {
guard let info = cloudInfo else {
self.init(coder: NSKeyedUnarchiver(forReadingWithData: NSData()))
return nil
}
self.init(coder: NSKeyedUnarchiver(forReadingWithData: info))
}
}
Actually in Swift 3, there seems to be a bug and a regression from Swift 2: returning nil from a failable intializer crash the runtime.

EXC_BAD_ACCESS to Typhoon Singleton Reference

I'm using the Typhoon Framework to integrate all of my core components. I'm working on my data layer (using FMDB instead of Core Data). I have a LocalDataStore class that handles the reading and writing of data to SQLite. This is a singleton class that has an initialization method that sets up the database. Then I have a PlayerDAO that references it.
When I launch the app, the LocalDataStore gets created and the initialization method gets called. It then goes to create the DAO class, and when it tries to access the LocalDataStore, I'm receiving an EXC_BAD_ACCESS error.
Turning on "Enable Zombie Objects" in the launch scheme, I get an additional error:
-[myapp.SQLiteLocalStore retain]: message sent to deallocated instance 0x1740ab5e0
Here's how I set things up in my Typhoon Assembly:
dynamic func config() -> TyphoonDefinition {
return TyphoonDefinition.configDefinitionWithName("MyApp.plist")
}
dynamic func localStore() -> AnyObject {
return TyphoonDefinition.withClass(SQLiteLocalStore.self, configuration: {
(definition) in
definition.injectProperty("databaseName", with: TyphoonConfig("sqlite.filename"))
definition.performAfterInjections("initDatabase")
definition.scope = .Singleton
})
}
dynamic func playerDAO() -> AnyObject {
return TyphoonDefinition.withClass(SQLitePlayerDAO.self, configuration: {
(definition) in
definition.injectProperty("localStore", with: self.localStore())
})
}
Looking at the breakpoint when the error occurs, it's happening on this line in TyphoonComponentFactory:
- (id)newOrScopeCachedInstanceForDefinition:(TyphoonDefinition *)definition args:(TyphoonRuntimeArguments *)args {
...
instance = [pool objectForKey:poolKey]; // line 431
...
}
poolKey = #"localStore"
The debugger says it's currently initializing playerDAO. The pool has only 1 key of "localStore" and the value is _NSZombie_myApp.SQLiteLocalStore
Any idea on what could be going wrong?
Well, changing definition.scope = .Singleton to definition.scope = .LazySingleton fixed it... and in my case, is probably a better approach anyway.
I'm still curious if I was doing something wrong to cause the memory error with the plain Singleton.

iOS Swift : EXC_BAD_ACCESS(code=EXC_i386_GPFLT ) regarding a singleton

My iOS app is returning this error.
EXC_BAD_ACCESS(code=EXC_i386_GPFLT )
This is occuring on return Singleton.instance Here is the code regarding the singleton I am using.
class var sharedData : SharedData {
struct Singleton {
static let instance = SharedData()
}
return Singleton.instance
}
Can someone help me understand this error and help me resolve it? Any suggestions or tips are appreciated it.
With Swift 1.2 there is an easier option to create singletons now:
class DataManager {
static let sharedInstance = DataManager()
/// To deny direct access, make your init function private if you want
private init() {
}
}
I was using a singleton as others have mentioned above,
static let sharedData = SharedData()
and it was crashing on a real device but not in the simulator. It turns out that I just needed to clean the project and rebuild.
Don't fall for false positives ;)
You can replace all your code with the following:
static let sharedData = SharedData()
I had a badly named function in my Swift singleton class, that must have been tripping up ARC when it was called. This class initializes another class from a file, and so I ended up with this signature:
func initOtherClass(otherClass: NSObject, URL fileURL: NSURL) -> Bool
Whoops. Changing the name from init to initialize solved the EXC_BAD_ACCESS errors. I hope this helps to save someone else some time.

Swift function that return two strings fail when its in loop

I Wrote a function that return two Strings, when calling the function regularly its works fine, but when I'm running the function through loop, I'm getting this error:
Thread 1: EXC_BAD_ACCESS (code=2, address=0xbfffcba0)
override func viewDidLoad()
{
super.viewDidLoad()
test()
}
func test()
{
var funcs = [checkButton]
var a = checkButton(value: 1) // Runs OK
for f in funcs{
var result = f(value: 1) // Fail
}
}
func checkButton(#value: Int) -> (location: String, pattern: String){
return ("abc","cba")
}
Update:
I'm using Xcode 6 beta 2, and running Mavericks on VMware Workstation.
Also, I've just created new clean project with that code and still getting the error.
This code runs fine for me. Your EXC_BAD_ACCESS must be coming from some other part of your code. Try setting a breakpoint and stepping through the code to find the line throwing the error.
From the “The Swift Programming Language.”
“An instance method can be called only on a specific instance of the type it belongs to. It cannot be called in isolation without an existing instance.”
checkButton() is an instance method, not a closure. It works in the first case because there is an implicit self. before checkButton(). It will not work in the second case.
If you want to make checkButton a closure you could declare it like so:
let checkButton = { (#value: Int) -> (location: String, pattern: String) in
return ("abc","cba")
}
I can confirm that it doesn't work for me either. Created a iOS single-view app from template, and added above code. crash. As an experiment, I took it out of the array (just f = self.checkButton) and got the same result.
I think it's a bug in the compiler.
First according to the book, a method is actually a function which is actually a closure, albeit one with special properties and restrictions. Shouldn't self.checkButton (or implicit version) be sufficient to "give it an existing instance", making it a closure? If MattL is correct that instance methods can't be used as closures, then the compiler shouldn't allow you to assign one to anything.
Second, the crash occurs on the exit, not on the call. And if you reference self in checkButton, (e.g. println(self.title) having previously set title), it works fine. That suggests that the instance is indeed known and operating, just something wrong on the return.
Third, changing it to a class method doesn't help. Changing these lines
var a = ViewController.checkButton(value: 1)
var funcs = [ViewController.checkButton]
class func checkButton(#value: Int) -> (location: String, pattern: String)
results in the same crash. I don't see any similar prohibition on context for class methods.
Fourth, if you simply change the return type from (location: String, pattern: String) to just String and return abc, then the whole thing works fine.
Fourth, if you wrap test and checkButton in a new class testClass, and then call it as below, it works:
class testClass {
func test()
{
var funcs = [checkButton]
var a = checkButton(value: 1) // Runs OK
for f in funcs {
var result = f(value: 1) // Fail
println(result)
}
}
func checkButton(#value: Int) -> (location: String, pattern: String){
return ("abc","cba")
}
}
class ViewController: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
let g = testClass()
g.test()
}
}
Now change testClass to testClass: NSObject and it crashes.
So it looks like the compiler is botching up a method return when called as a closure with a tuple in a Obj-C subclass. When I put it like that, I must say that it's not terribly surprising nobody's noticed yet; you're really pushing the edge here!
More practically, in the meantime, if it's helpful, an alternative to changing your method to a closure is to keep it unchanged and just wrap it as you put it in the array:
var funcs = [{value in self.checkButton(value: value)}]
This seems to work.

Resources