Mysterious EXC_BAD_ACCESS in simple code - swift

I have some project where I created convenient architecture for my needing and all things was fine until I encountered mysterious crashes with EXC_BAD_ACCESS at runtime. I posted here the smallest code which represents the issue and here is the explanation:
Imagine some protocol and another one which is first's child:
protocol Base {
static var key: String { get }
}
protocol BaseChild: Base {
}
And here is some simple implementation:
struct ChildEntity: BaseChild {
static var key: String {
return "key"
}
}
Then, I have some class which works with such entities:
class Worker {
static var defaultWorker: Worker? // will explain later
func work<T: Base>(entity: T) {
print(T.key)
}
}
And I also have some subclass of Worker:
class ChildWorker: Worker {
override func work<T: BaseChild>(entity: T) {
print(T.key)
}
}
So far so good. Then I added static defaultWorker var to my Worker class to make access to my default worker easier, this allows me to create an extension for my Base protocol which will work with my defaultWorker:
extension Base {
func work() {
Worker.defaultWorker?.work(entity: self)
}
}
However this generates EXC_BAD_ACCESS at runtime. Here is simple usage:
class Test {
static func run() {
let object = ChildEntity()
let worker = ChildWorker()
worker.work(entity: object) // OK here
Worker.defaultWorker = worker
object.work() // EXC_BAD_ACCESS here
}
}
I tested this on both Xcode 8 and Xcode 9 with Swift 3 and Swift 4. Please help me solve this issue

I wonder why you override func work<T: Base>(entity: T) to override func work<T: BaseChild >(entity: T)?
Is not that supposed to be override func work<T: Base>(entity: T)?

Related

Not able to override extensions function in another extension - Swift 4 [duplicate]

I've been working on an iOS application in Swift (much of it being moved from Objective-C). I'm using Core Data and trying to use extensions to add functionality to classes auto-generated from my model. One thing I readily did in Objective-C was to add a method in a category on class A and override that method in a category on class B (which derived from A), and I was hoping to do the same in Swift.
For a while now I've had the following code in my project (and this is just one example), and though I have not used the functionality yet, the compiler has worked just fine compiling this code:
// From CellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(CellType)
class CellType: NSManagedObject {
#NSManaged var maxUses: NSNumber
#NSManaged var useCount: NSNumber
// Other properties removed for brevity
}
// From SwitchCellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(SwitchCellType)
class SwitchCellType: CellType {
#NSManaged var targetCellXIndex: NSNumber
#NSManaged var targetCellYIndex: NSNumber
#NSManaged var targetCellType: CellType
// Other properties removed for brevity
}
// From CellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension CellType
{
var typeLabel : String { get { return "Empty"; } }
func isEqualToType(otherCellType : CellType) -> Bool
{
return (self.typeLabel == otherCellType.typeLabel &&
self.maxUses.isEqualToNumber(otherCellType.maxUses) &&
self.useCount.isEqualToNumber(otherCellType.useCount));
}
// Code removed for brevity
}
// From SwitchCellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension SwitchCellType // YES, this compiles with the overrides!
{
override var typeLabel : String { get { return "Switch"; } }
override func isEqualToType(otherCellType : CellType) -> Bool
{
var answer = false;
if let otherSwitchCellType = otherCellType as? SwitchCellType
{
answer = super.isEqualToType(otherCellType) &&
self.targetCellXIndex.isEqualToNumber(otherSwitchCellType.targetCellXIndex) &&
self.targetCellYIndex.isEqualToNumber(otherSwitchCellType.targetCellYIndex) &&
self.targetCellType.isEqualToType(otherSwitchCellType.targetCellType);
}
return answer;
}
// Code removed for brevity
}
Hopefully some kind Swift expert out there already sees my issue, but here's how I found out about it: Recently I tried to add similar functionality using methods that have parameters and/or return values that are not built in types, but I started getting this error: Declarations in extensions cannot override yet.
To explore this issue I added the following to one of my swift files, thinking it would compile just fine:
class A
{
}
class B : A
{
}
extension A
{
var y : String { get { return "YinA"; } }
}
extension B
{
override var y : String { get { return "YinB"; } } // Compiler error (see below) -- What??
}
To my surprise, I received the same compiler error (Declarations in extensions cannot override yet). What? But I've used that patter several times already without compiler errors.
Questions:
First, are there certain rules about overriding in extensions such that in some cases it is supposed to work but in other cases it is not? Second (and more disconcerting) why does it seem that the Swift compiler is so inconsistent? What am I missing here? Please help me restore my faith in Swift.
UPDATE:
As noted in the correct answer by Martin R, it seems you can override methods in the current version of Swift (1.1 via Xcode 6.1) as long as they (1) involve only classes derived from NSObject and (2) do not use the inout modifier. Here's some examples:
class A : NSObject { }
class B : A { }
class SubNSObject : NSObject {}
class NotSubbed {}
enum SomeEnum { case c1, c2; }
extension A
{
var y : String { get { return "YinA"; } }
func f() -> A { return A(); }
func g(val: SubNSObject, test: Bool = false) { }
func h(val: NotSubbed, test: Bool = false) { }
func j(val: SomeEnum) { }
func k(val: SubNSObject, inout test: Bool) { }
}
extension B
{
// THESE OVERIDES DO COMPILE:
override var y : String { get { return "YinB"; } }
override func f() -> A { return A(); }
override func g(val: SubNSObject, test: Bool) { }
// THESE OVERIDES DO NOT COMPILE:
//override func h(val: NotSubbed, test: Bool = false) { }
//override func j(val: SomeEnum) { }
//override func k(val: SubNSObject, inout test: Bool) { }
}
It seems that overriding methods and properties in an extension works with the
current Swift (Swift 1.1/Xcode 6.1) only for Objective-C compatible
methods and properties.
If a class is derived from NSObject then all its members are automatically available
in Objective-C (if possible, see below). So with
class A : NSObject { }
your example code compiles and works as expected. Your Code Data extension overrides
work because NSManagedObject is a subclass of NSObject.
Alternatively, you can use the #objc attribute for a method or property:
class A { }
class B : A { }
extension A
{
#objc var y : String { get { return "YinA" } }
}
extension B
{
#objc override var y : String { get { return "YinB" } }
}
Methods which are not representable in Objective-C cannot be marked with #objc
and cannot be overridden in a subclass extension. That applies for example to
methods having inout parameters or parameters of an enum type.
I experienced this on Xcode9. Closing and reopening Xcode worked for me. Probably a bug in the compiler.

How to define initializers in a protocol extension?

protocol Car {
var wheels : Int { get set}
init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.wheels = wheels
}
}
on self.wheels = wheels i get the error
Error: variable 'self' passed by reference before being initialized
How can I define the initializer in the protocol extension?
As you can see this doesn't work under these circumstances because when compiling, one has to make sure that all properties are initialized before using the struct/enum/class.
You can make another initializer a requirement so the compiler knows that all properties are initialized:
protocol Car {
var wheels : Int { get set }
// make another initializer
// (which you probably don't want to provide a default implementation)
// a protocol requirement. Care about recursive initializer calls :)
init()
init(wheels: Int)
}
extension Car {
// now you can provide a default implementation
init(wheels: Int) {
self.init()
self.wheels = wheels
}
}
// example usage
// mark as final
final class HoverCar: Car {
var wheels = 0
init() {}
}
let drivableHoverCar = HoverCar(wheels: 4)
drivableHoverCar.wheels // 4
As of Xcode 7.3 beta 1 it works with structs as expected but not with classes since if they are not final the init(wheels: Int) in the protocol is a required init and it can be overridden therefore it cannot be added through an extension. Workaround (as the complier suggests): Make the class final.
Another workaround (in depth; without final class)
To work with classes without making them final you can also drop the init(wheels: Int) requirement in the protocol. It seems that it behaves no different than before but consider this code:
protocol Car {
var wheels : Int { get set }
init()
// there is no init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.init()
print("Extension")
self.wheels = wheels
}
}
class HoverCar: Car {
var wheels = 0
required init() {}
init(wheels: Int) {
print("HoverCar")
self.wheels = wheels
}
}
// prints "HoverCar"
let drivableHoverCar = HoverCar(wheels: 4)
func makeNewCarFromCar<T: Car>(car: T) -> T {
return T(wheels: car.wheels)
}
// prints "Extension"
makeNewCarFromCar(drivableHoverCar)
So if you make a Car from a generic context where the type on which you call init is only to be known as Car the extension initializer is called even though an initializer is defined in HoverCar. This only occurs because there is no init(wheels: Int) requirement in the protocol.
If you add it you have the former problem with declaring the class as final but now it prints two times "HoverCar". Either way the second problem probably never occurs so it might be a better solution.
Sidenote: If I have made some mistakes (code, language, grammar,...) you're welcome to correct me :)
My understanding is that this isn't possible, because the protocol extension can't know which properties the conforming class or struct has - and therefore cannot guarantee they are correctly initialized.
If there are ways to get around this, I'm very interested to know! :)
#Qbyte is correct.
In addition, you can take a look at my Configurable
In that I have Initable protocol
public protocol Initable {
// To make init in protocol extension work
init()
}
public extension Initable {
public init(#noescape block: Self -> Void) {
self.init()
block(self)
}
}
Then in order to conform to it
extension Robot: Initable { }
I have 2 ways, using final or implement init
final class Robot {
var name: String?
var cute = false
}
class Robot {
var name: String?
var cute = false
required init() {
}
}
May not be the same but in my case instead of using init I used a static func to return the object of the class.
protocol Serializable {
static func object(fromJSON json:JSON) -> AnyObject?
}
class User {
let name:String
init(name:String) {
self.name = name
}
}
extension User:Serializable {
static func object(fromJSON json:JSON) -> AnyObject? {
guard let name = json["name"] else {
return nil
}
return User(name:name)
}
}
Then to create the object I do something like:
let user = User.object(fromJSON:json) as? User
I know its not the best thing ever but its the best solution I could find to not couple business model with the data layer.
NOTE: I'm lazy and I coded everything directly in the comment so if something doesn't work let me know.

Swift Mocking Class

As far as I know there is no possible solution for mocking and stubbing methods in swift like we were used in objc with OCMock, Mockito, etc.
I'm aware of technique described here. It is quite useful in some cases, but now I had a deadlock :)
I had a service layer where I had something like contracts(calling this method with this params will return that object as callback). This is one(greatly simplified) example:
class Bar
{
func toData() -> NSData
{
return NSData()
}
}
class Foo
{
class func fromData(data: NSData) -> Foo
{
return Foo()
}
}
class ServerManager
{
let sharedInstance = ServerManager()
class func send(request: NSData, response: (NSData)->())
{
//some networking code unrelated to the problem
response(NSData())
}
}
class MobileService1
{
final class func Contract1(request: Bar, callback: (Foo) -> ())
{
ServerManager.send(request.toData()) { responseData in
callback(Foo.fromData(responseData))
}
}
//Contract2(...), Contract3(...), etc
}
Therefore somewhere in the code I had following scenario:
func someWhereInTheCode(someBool: Bool, someObject: Bar)
{
if someBool
{
MobileService1.Contract1(someObject) { resultFoo in
//self.Foo = resultFoo
}
}
else
{
//MobileService1.Contract2(...)
}
}
And the question now is how the heck could I test this? Is there better(for testing) alternative for code structure without touching contracts themselves?
Better late than never I found a solution. Just make dependency injection of the MobileService1(or better of it's interface) and then mock it easily:
//declaring interface
protocol MobileServiceContracts: class {
static func Contract1(request: Bar, callback: (Foo) -> ())
}
//make implementation to conform to interface
class MobileService1 : MobileServiceContracts
{
final class func Contract1(request: Bar, callback: (Foo) -> ())
{
ServerManager.send(request.toData()) { responseData in
callback(Foo.fromData(responseData))
}
}
//Contract2(...), Contract3(...), etc
}
//inject service
func someWhereInTheCode(someBool: Bool, someObject: Bar, serviceProvider: MobileServiceContracts.Type = MobileService1.self)
{
if someBool
{
serviceProvider.Contract1(someObject) { resultFoo in
//self.Foo = resultFoo
}
}
else
{
//MobileService1.Contract2(...)
}
}
Now you can easily change service in your tests:
class MockedMobileService1: MobileServiceContracts
{
static func Contract1(request: Bar, callback: (Foo) -> ()) {
//do whatever with the mock
}
}
someWhereInTheCode(false, someObject: Bar(), serviceProvider: MockedMobileService1.self)
And the best part is with default values you can still call it the old way(not braking change):
someWhereInTheCode(false, someObject: Bar())
Meanwhile, you can do mocking with Cuckoo, which is similar to Mockito.
Example Classes:
class ExampleObject {
var number: Int = 0
func evaluate(number: Int) -> Bool {
return self.number == number
}
}
class ExampleChecker {
func check(object: ExampleObject) -> Bool {
return object.evaluate(5)
}
}
Example Test:
#testable import App
import Cuckoo
import XCTest
class ExampleCheckerTests: XCTestCase {
func testCheck() {
// 1. Arrange
let object = MockExampleObject().spy(on: ExampleObject())
stub(object) { object in
when(object.evaluate(any())).thenDoNothing()
}
let checker = ExampleChecker()
// 2. Action
checker.check(object)
// 3. Assert
_ = verify(object).number.get
verify(object).evaluate(any())
verifyNoMoreInteractions(object)
}
}
There’s a much better framework called Mockingbird.
It’s super simple to setup and dynamically builds your mocks as the application builds to run the tests. Here’s an article that explains how some of it works

Can you override between extensions in Swift or not? (Compiler seems confused!)

I've been working on an iOS application in Swift (much of it being moved from Objective-C). I'm using Core Data and trying to use extensions to add functionality to classes auto-generated from my model. One thing I readily did in Objective-C was to add a method in a category on class A and override that method in a category on class B (which derived from A), and I was hoping to do the same in Swift.
For a while now I've had the following code in my project (and this is just one example), and though I have not used the functionality yet, the compiler has worked just fine compiling this code:
// From CellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(CellType)
class CellType: NSManagedObject {
#NSManaged var maxUses: NSNumber
#NSManaged var useCount: NSNumber
// Other properties removed for brevity
}
// From SwitchCellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(SwitchCellType)
class SwitchCellType: CellType {
#NSManaged var targetCellXIndex: NSNumber
#NSManaged var targetCellYIndex: NSNumber
#NSManaged var targetCellType: CellType
// Other properties removed for brevity
}
// From CellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension CellType
{
var typeLabel : String { get { return "Empty"; } }
func isEqualToType(otherCellType : CellType) -> Bool
{
return (self.typeLabel == otherCellType.typeLabel &&
self.maxUses.isEqualToNumber(otherCellType.maxUses) &&
self.useCount.isEqualToNumber(otherCellType.useCount));
}
// Code removed for brevity
}
// From SwitchCellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension SwitchCellType // YES, this compiles with the overrides!
{
override var typeLabel : String { get { return "Switch"; } }
override func isEqualToType(otherCellType : CellType) -> Bool
{
var answer = false;
if let otherSwitchCellType = otherCellType as? SwitchCellType
{
answer = super.isEqualToType(otherCellType) &&
self.targetCellXIndex.isEqualToNumber(otherSwitchCellType.targetCellXIndex) &&
self.targetCellYIndex.isEqualToNumber(otherSwitchCellType.targetCellYIndex) &&
self.targetCellType.isEqualToType(otherSwitchCellType.targetCellType);
}
return answer;
}
// Code removed for brevity
}
Hopefully some kind Swift expert out there already sees my issue, but here's how I found out about it: Recently I tried to add similar functionality using methods that have parameters and/or return values that are not built in types, but I started getting this error: Declarations in extensions cannot override yet.
To explore this issue I added the following to one of my swift files, thinking it would compile just fine:
class A
{
}
class B : A
{
}
extension A
{
var y : String { get { return "YinA"; } }
}
extension B
{
override var y : String { get { return "YinB"; } } // Compiler error (see below) -- What??
}
To my surprise, I received the same compiler error (Declarations in extensions cannot override yet). What? But I've used that patter several times already without compiler errors.
Questions:
First, are there certain rules about overriding in extensions such that in some cases it is supposed to work but in other cases it is not? Second (and more disconcerting) why does it seem that the Swift compiler is so inconsistent? What am I missing here? Please help me restore my faith in Swift.
UPDATE:
As noted in the correct answer by Martin R, it seems you can override methods in the current version of Swift (1.1 via Xcode 6.1) as long as they (1) involve only classes derived from NSObject and (2) do not use the inout modifier. Here's some examples:
class A : NSObject { }
class B : A { }
class SubNSObject : NSObject {}
class NotSubbed {}
enum SomeEnum { case c1, c2; }
extension A
{
var y : String { get { return "YinA"; } }
func f() -> A { return A(); }
func g(val: SubNSObject, test: Bool = false) { }
func h(val: NotSubbed, test: Bool = false) { }
func j(val: SomeEnum) { }
func k(val: SubNSObject, inout test: Bool) { }
}
extension B
{
// THESE OVERIDES DO COMPILE:
override var y : String { get { return "YinB"; } }
override func f() -> A { return A(); }
override func g(val: SubNSObject, test: Bool) { }
// THESE OVERIDES DO NOT COMPILE:
//override func h(val: NotSubbed, test: Bool = false) { }
//override func j(val: SomeEnum) { }
//override func k(val: SubNSObject, inout test: Bool) { }
}
It seems that overriding methods and properties in an extension works with the
current Swift (Swift 1.1/Xcode 6.1) only for Objective-C compatible
methods and properties.
If a class is derived from NSObject then all its members are automatically available
in Objective-C (if possible, see below). So with
class A : NSObject { }
your example code compiles and works as expected. Your Code Data extension overrides
work because NSManagedObject is a subclass of NSObject.
Alternatively, you can use the #objc attribute for a method or property:
class A { }
class B : A { }
extension A
{
#objc var y : String { get { return "YinA" } }
}
extension B
{
#objc override var y : String { get { return "YinB" } }
}
Methods which are not representable in Objective-C cannot be marked with #objc
and cannot be overridden in a subclass extension. That applies for example to
methods having inout parameters or parameters of an enum type.
I experienced this on Xcode9. Closing and reopening Xcode worked for me. Probably a bug in the compiler.

Compiler error for nested class with override func - Swift Xcode6

I have a simple Cocoa Touch Framework project with Swift code only. In my unit test class I want to do mocking so I created a mock class which inherits from the type I want to mock:
func testFirstClassMocking() {
class MockSecondClass: SecondClass {
var mockedResult = "My mocked value"
override func printSecondLogEntry(logEntry: String) -> String {
return mockedResult
}
}
let mock = MockSecondClass()
var firstClass = FirstClass(secondClass: mock)
let result = firstClass.printFirstLogEntry("whatever")
XCTAssertEqual("My mocked value", result);
}
This result in a generic compiler error:
Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
Now, when I take the nested class out of the function and nest just in my testing class - everything is great. Code compiles and my unit test runs great. Is class nesting in functions not allowed any more?
My Xcode ver: Version 6.0.1 (6A317)
EDIT: one other thing - if I remove the override of the func - the compiler has no issues. Obviously I need the override func to be able to return a value I need in my unit test when my mock object runs.
I thought you might want to know that the following 'mock' of your mock test is compiling and passing. Let me know if I missed something about your code as it is in your question. If I did not miss anything, however, then the cause of the error is something about your code that did not make into the question. Hope that helps you either find the culprit or reformulate the question:
import XCTest
class FirstClass {
let secondClass: SecondClass
init(secondClass: SecondClass) {
self.secondClass = secondClass
}
func printFirstLogEntry(entry: String) -> String {
var fullLog = self.secondClass.printSecondLogEntry(entry)
return fullLog
}
}
class SecondClass {
func printSecondLogEntry(logEntry: String) -> String {
return logEntry
}
}
class CommandLineTests: XCTestCase {
func testFirstClassMocking() {
class MockSecondClass: SecondClass {
override func printSecondLogEntry(logEntry: String) -> String {
return logEntry
}
}
let mock = MockSecondClass()
var firstClass = FirstClass(secondClass: mock)
let result = firstClass.printFirstLogEntry("whatever")
XCTAssertEqual("whatever", result);
}
}