When creating a child class object which extends the generic base class, if it is created using convenience constructor, a callback contains the generic object will crash in the runtime because of the incorrect/corrupted object being passed back.
It is new in Swift3.1. There is no such problem in Swift 3.0.
It only happens when creating an object using convenience constructor.
protocol Initializable {
init()
}
class MyClass: Initializable {
required init() {}
func log() {
print("Hello")
}
}
class Parent<T: Initializable> {
typealias Callback = (T) -> Void
init(callback: Callback) {
callback(T())
}
}
class Child: Parent<MyClass> {
convenience init(value: Int, callback: Callback) {
self.init(callback: callback)
}
override init(callback: Callback) {
super.init(callback: callback)
}
}
let _ = Child { data in
data.log() //This is OK
}
let _ = Child(value: 0) { data in
data.log() //This will crash under swift3.1
}
Is it a language bug? Or am I doing something not supposed to be?
Related
I try to init a class in a generic way with parameters but it doesn't work...
protocol EntityCreator: class {
func createEntity<EntityType: EntityClass & EntityCreatorInitializable>(type: EntityType.Type, _ initialize: #escaping (EntityType) -> Void)
}
protocol EntityCreatorInitializable {
init(entityCreator: EntityCreator)
}
class EntityClass: NSObject { }
class MyClass: EntityClass, EntityCreatorInitializable {
required init(entityCreator: EntityCreator) {
super.init()
// use the entityCreator
}
}
// On the entity creator implementation :
class EntityCreatorImplementation: EntityCreator {
var toAdd = Set<EntityClass>()
func createEntity<EntityType: EntityClass & EntityCreatorInitializable>(type: EntityType.Type, _ initialize: #escaping (EntityType) -> Void) {
// This creation doesn't work...
let newEntity = EntityType(entityCreator: self)
initialize(newEntity)
self.toAdd.insert(newEntity)
}
}
The error I have at compilation is
Non-nominal type 'EntityType' does not support explicit initialization
Any Ideas on how to achieve this ?
Thanks !!
EDIT : I added the definition of EntityClass. In my project it is a GKEntity, but the problem is the same with just NSObject
EDIT : added the toAdd Set, forgot to declare it (but used it in the createEntity method)
Change
EntityType: EntityClass & EntityCreatorInitializable
to
EntityType: EntityCreatorInitializable
if you want to be able to initialize a lot of different types, you should define a new protocol, check this answer
protocol EntityCreator: class {
func createEntity<EntityType: EntityClass & EntityCreatorInitializable>(type: EntityType.Type, _ initialize: #escaping (EntityType) -> Void)
}
protocol EntityCreatorInitializable {
init(entityCreator: EntityCreator)
}
class EntityClass: NSObject { }
class MyClass: EntityClass, EntityCreatorInitializable {
public required init(entityCreator: EntityCreator) {
super.init()
// use the entityCreator
}
}
// On the entity creator implementation :
class EntityCreatorImplementation: EntityCreator {
func createEntity<EntityType: EntityCreatorInitializable>(type: EntityType.Type, _ initialize: #escaping (EntityType) -> Void) {
// This creation doesn't work...
let newEntity = EntityType.init(entityCreator:self)
// initialize(newEntity)
// self.toAdd.insert(newEntity)
}
I am trying to create a wrapper for my API return wrapper class for my project.
these are my classes
class Wrapper<T> {
let message = "Hello World"
let wrapped = T.self
public func getData() -> T.Type {
return wrapped
}
}
class Object {
let number = 100
public func getNumber() -> Int {
return number
}
}
class SecondObject {
let name = "Second Object"
public func getName() -> String {
return name
}
}
What I want to achieve is, is there any way I can call the Object function like this
let example = Wrapper<Object>()
example.getData().getNumber() // <<-- This is not working
let secondExample = Wrapper<SecondObject>()
secondExample.getData().getName() // <<-- This is not working
The error in my playground is this
error: instance member 'getNumber' cannot be used on type 'Object'
If you notice the Wrapper class, there is message property which will be used for all my API return object model
So my goal is, I could simply call the Wrapper class together with my object model class and just call the function that is inside the object model class.
I am still learning about generic in swift. What am I missing here?
You don't set wrapped to anything useful. You ned to set it to an instance of T. So you can pass a Tinto the constructor
class Wrapper<T>
{
let wrapped: T
init(wrapped: T)
{
self.wrapped = wrapped
}
}
Or you can have the class construct an instance of T, but if you want to do that, you need to tell it how to construct the instance. For example:
class Wrapper<T>
{
let wrapped: T
init()
{
self.wrapped = T() // << error!
}
}
won't work because the compiler knows nothing about T, not even if it has an init. You can change that with a protocol
protocol Initable
{
init()
}
class Wrapper<T: Initable>
{
let wrapped: T
init()
{
self.wrapped = T()
}
}
And you can apply the protocol to any type you like with an extension. In most cases the extension can be empty because mot types already have an init() method. For example:
class MyClass
{
init() { /* do stuff */ }
}
extension MyClass: Initable {}
class MyOtherClass
{
init(number: Int) { /* do stuff */ }
}
extension MyOtherClass: Initable
{
init() { self.init(number: 0) }
}
Another option is to supply a closure to the wrapper's init.
class Wrapper<T>
{
let wrapped: T
init(factory: ()-> T)
{
self.wrapped = factory()
}
}
let w = Wrapper() { return Array<Int>() }
Normally you'd only do this if you wanted to create multiple instances i.e. you'd keep a reference to the closure and call it each time you needed a new instance.
class Wrapper<T> {
private var wrapped: T // Storing your object of T type
init(value: T) { // init with instance of T
wrapped = value
}
public func getData() -> T { //returning instance of T
return wrapped
}
}
class Object {
let number = 100
public func getNumber() -> Int {
return number
}
}
let o = Object()
let example = Wrapper(value: o) // Here we creating instance of Wrapper with instance of Object
example.getData().getNumber()
How about this , in your example changing the type of wrapped from non-optional to an optional variable type.
class Wrapper {
let message = "Hello World"
var wrapped : T?
public func getData() -> T? {
return wrapped
}
}
class Object {
let number = 100
public func getNumber() -> Int {
return number
}
}
class SecondObject {
let name = "Second Object"
public func getName() -> String {
return name
}
}
and then using it as below
let example = Wrapper()
example.wrapped = Object()
let result1 = example.getData()?.getNumber() // ()
secondExample.wrapped = SecondObject()
let result2 = secondExample.getData()?.getName()
if let val1 = result1 , let val2 = result2 {
print("result1 = \(val1) result2 = \(val2)" )
}
I have a class cluster--when I create as instance of Class from JSON, I want to be able to return a subclass of Class. However I can't seem to make the types work out.
Seems the instance of Subclass should be convertable to Class. Isn't Class of type Self here?
Help.
protocol JSONSerializable
{
static func withJSONRepresentation( json:Any? ) -> Self?
}
class Class : JSONSerializable
{
static func withJSONRepresentation( json:Any? ) -> Self?
{
return Subclass( jsonRepresentation: json )
}
init?( jsonRepresentation:Any? )
{
// init instance here
}
}
class Subclass : Class
{
override init?( jsonRepresentation:Any? )
{
// init instance here
}
}
Is this what you're after? I am using self.init in the return, which therefore needs a required init.
protocol JSONSerializable
{
static func withJSONRepresentation( json:Any? ) -> Self?
}
class Class : JSONSerializable
{
static func withJSONRepresentation( json:Any? ) -> Self?
{
return self.init( jsonRepresentation: json )
}
required init( jsonRepresentation:Any? )
{
}
}
class Subclass : Class
{
required init( jsonRepresentation:Any? )
{
super.init(jsonRepresentation: jsonRepresentation)
}
}
print(Class.withJSONRepresentation(nil)) // -> Class
print(Subclass.withJSONRepresentation(nil)) // -> Subclass
EDIT:
An alternative is to return a JSONSerializable (or Class) instance, but then depending on your needs, you may have to downcast to the required type.
The problem with your existing code is the compiler cannot guarantee you will meet your promise of returning an instance of Self. For example, when calling Subclass.withJSONRepresentation, your code could return an instance of Class (or anything else), which breaks the promise. Actually this is the crux of the matter - with your current code, if the json means it needs to return a Class, you would have to call it on the Class static func, whereas if it should return a Subclass, you would have to call it on the Subclass static func. "Self" does not include subclasses, so if called on the Class static func, it must only ever return a Class instance, not a subclass.
protocol JSONSerializable
{
static func withJSONRepresentation( json:Any? ) -> JSONSerializable?
}
class Class : JSONSerializable
{
static func withJSONRepresentation( json:Any? ) -> JSONSerializable?
{
return Subclass( jsonRepresentation: json )
}
init?( jsonRepresentation:Any? )
{
// init instance here
}
}
class Subclass : Class
{
}
print(Class.withJSONRepresentation(nil))
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
Is there an equivalent syntax or technique for Anonymous class in Swift?
Just for clarification Anonymous class in Java example here - http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
Thanks!
There is no equivalent syntax, as far as I know.
Regarding equivalent techniques, theoretically you could use closures and define structs and classes inside them. Sadly, I can't get this to work in a playground or project without making it crash. Most likely this isn't ready to be used in the current beta.
Something like...
protocol SomeProtocol {
func hello()
}
let closure : () -> () = {
class NotSoAnonymousClass : SomeProtocol {
func hello() {
println("Hello")
}
}
let object = NotSoAnonymousClass()
object.hello()
}
...currently outputs this error:
invalid linkage type for global declaration
%swift.full_heapmetadata* #_TMdCFIv4Test7closureFT_T_iU_FT_T_L_19NotSoAnonymousClass
LLVM ERROR: Broken module found, compilation aborted!
Command /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift failed with exit code 1
You can also create a basic empty class that acts like a bare protocol, and pass a closure to the init function that overrides anything you want, like this:
class EmptyClass {
var someFunc: () -> () = { }
init(overrides: EmptyClass -> EmptyClass) {
overrides(self)
}
}
// Now you initialize 'EmptyClass' with a closure that sets
// whatever variable properties you want to override:
let workingClass = EmptyClass { ec in
ec.someFunc = { println("It worked!") }
return ec
}
workingClass.someFunc() // Outputs: "It worked!"
It is not technically 'anonymous' but it works the same way. You are given an empty shell of a class, and then you fill it in or override whatever parameters you want when you initialize it with a closure.
It's basically the same, except instead of fulfilling the expectations of a protocol, it is overriding the properties of a class.
For example, Java listener/adapter pattern would be translated to Swift like this:
protocol EventListener {
func handleEvent(event: Int) -> ()
}
class Adapter : EventListener {
func handleEvent(event: Int) -> () {
}
}
var instance: EventListener = {
class NotSoAnonymous : Adapter {
override func handleEvent(event: Int) {
println("Event: \(event)")
}
}
return NotSoAnonymous()
}()
instance.handleEvent(10)
(Crashing the compiler on Beta 2)
The problem is, you always have to specify a name. I don't think Apple will ever introduce anonymous classes (and structs etc.) because it would be pretty difficult to come with a syntax that doesn't collide with the trailing closures.
Also in programming anonymous things are bad. Naming things help readers to understand the code.
No anonymous class syntax in Swift. But, you can create a class inside a class and class methods:
class ViewController: UIViewController {
class anonymousSwiftClass {
func add(number1:Int, number2:Int) -> Int {
return number1+number2;
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
class innerSwiftClass {
func sub(number1:Int, number2:Int) -> Int {
return number1-number2;
}
}
var inner = innerSwiftClass();
println(inner.sub(2, number2: 3));
var anonymous = anonymousSwiftClass();
println(anonymous.add(2, number2: 3));
}
}
This is what I ended up doing (Observer pattern). You can use closures in a similar way you would use anonymous classes in Java. With obvious limitations of course.
class Subject {
// array of closures
var observers: [() -> Void] = []
// #escaping says the closure will be called after the method returns
func register(observer: #escaping () -> Void) {
observers.append(observer)
}
func triggerEvent() {
observers.forEach { observer in
observer()
}
}
}
var subj = Subject()
// you can use a trailing closure
subj.register() {
print("observerd")
}
// or you can assign a closure to a variable so you can maybe use the reference to removeObserver() if you choose to implement that method
var namedObserver: () -> Void = {
print("named observer")
}
subj.register(observer: namedObserver)
subj.triggerEvent()
// output:
// observerd
// named observer
If you want to inline a click handler in Java style fashion, first define your closure as a variable in your button class:
var onButtonClick: () -> Void = {}
Then add a method to accept the closure as parameter and store it in the variable for later use:
func onClick(label: String, buttonClickHandler: #escaping () -> Void) {
button.label = label
onButtonClick = buttonClickHandler
}
Whenever the closure should be executed, call it in your button class:
onButtonClick()
And this is how to set the action that should occur on click:
newButton.onClick(label: "My button") { () in
print("button clicked")
}
You can also accept multiple parameters. For example, a toggle button may be handled like this:
var buttonClicked: (_ isOn: Bool) -> Void { set get }
Simply use a struct for defining the interface via function values and then anonymously implement it from a function, as is a very common way to write objects in JavaScript.
The function is only required for creating a private scope for the object returned.
import Foundation
struct Logger {
let info: (String) -> ()
let error: (String) -> ()
}
func createSimpleLogger() -> Logger {
var count = 0
func number() -> Int {
count += 1
return count
}
return Logger(
info: { message in
print("INFO - #\(number()) - \(message)")
},
error: { message in
print("ERROR - #\(number()) - \(message)")
}
)
}
let logger = createSimpleLogger()
logger.info("Example info log message")
logger.error("Example error log message")
Output:
INFO - #1 - Example info log message
ERROR - #2 - Example error log message