here I have a Protocol:
protocol CrashProtocol {
associatedtype T
static func tryCrash(_ dummyInt: Int,
with closure: ((T) -> Void))
}
A Base class that implements it:
class Crash<M>: CrashProtocol {
typealias T = M
class func tryCrash(_ dummyInt: Int,
with closure: ((M) -> Void)) {
print("Crash tryCrash")
}
}
And a derived class inherit the base class:
class DerivedCrash: Crash<DummyObject> {
override class func tryCrash(_ dummyInt: Int, with closure: ((DummyObject) -> Void)) {
super.tryCrash(dummyInt, with: closure)
print("Derived tryCrash")
let obj = DummyObject.init()
closure(obj)
}
}
Now whenever I try
DerivedCrash.tryCrash(1) { _ in
print("Never reach here")
}
I get a "EXC_BAD_ACCESS" crash. You can find my testing code here.
I've done my share of debugging, but only find out that the memory address causing the crash points to a Swift.Int instance, which I do not use..
And if I change the calling code a little bit, the code would crash after the closure being executed..
DerivedCrash.tryCrash(1) { (obj: DummyObject) in
//print("Never reach here")
print("print as expected and then crash")
}
If anyone could shred in some light, I would be highly appreciated..
I have added NSObject to associatedtype and now it doesn't crash.
It doesn't answer your question, but maybe this temp solution will help you
protocol CrashProtocol {
associatedtype T: NSObject
static func tryCrash(_ dummyInt: Int,
with closure: ((T) -> Void))
}
class Crash<M:NSObject>: CrashProtocol {
typealias T = M
class func tryCrash(_ dummyInt: Int,
with closure: ((M) -> Void)) {
print("Crash tryCrash")
}
}
Related
TL;DR:
How does an NSObject's self variable acquire the type (T) -> () -> T?
Remarks
I can see why the use of self this way is not legal. But I am trying to make sense of the second error message.
The Code
struct DummyStorer {
let dummy: Dummy
}
struct Dummy {
let storer = DummyStorer(dummy: self)
// Use of unresolved identifier 'self'
// OK, that's reasonable. But...
}
class Dummy : NSObject {
let storer = DummyStorer(dummy: self)
// Cannot convert value of type '(Dummy) -> () -> Dummy' to expected argument type 'Dummy'
// ... how does the compiler arrive at this?
}
It is part of NSObjectProtocol
public protocol NSObjectProtocol {
func isEqual(_ object: Any?) -> Bool
var hash: Int { get }
var superclass: AnyClass? { get }
func `self`() -> Self // << here !!
I'm currently writing and database access class for two database APIs (realm and Firestore). With the intention to slim down the code i try to solve the whole thing a little sleaker with generics (#1). Unfortunately, it's not working. Where do I miss the point?
I tried with defining associatedtypes (#2) and setting them within the RealmAccessStragy class. But on this point the compiler returns error if try to access the protocol via the PersistenceController.
I am grateful for any help!
APPROACH #1
enum DataResult<T> {
case success(T)
case failure(Error)
}
protocol DataApiAccess: AnyObject {
func read<U, T>(primaryKey: U, completion: #escaping ((DataResult<T>) -> Void))
}
class RealmAccessStrategy {
...
func read<U, T>(primaryKey: U, completion: #escaping ((DataResult<T>) -> Void)) {
guard let realmObject = realmInstance.object(ofType: realmObjectType, forPrimaryKey: primaryKey) else {
completion(.failure(RealmAccessError.noObject))
return
}
completion(.success(realmObject)) // ERROR: Member 'success' in 'DataResult<_>' produces result of type 'DataResult<T>', but context expects 'DataResult<_>'
}
}
// Later implementation
class PersistenceController {
private let strategy: DataApiAccess
init(use: DataApiAccess) {
self.strategy = use
}
func load<U, T>(primaryKey: U, completion: #escaping ( (DataResult<T>) -> Void ) ) {
strategy.read(primaryKey: primaryKey, completion: completion)
}
}
🆘 ERROR: Member 'success' in 'DataResult<>' produces result of type 'DataResult', but context expects 'DataResult<>'
APPROACH #2
enum DataResult<T> {
case success(T)
case failure(Error)
}
protocol DataApiAccess {
associatedtype ReturnType
func read(primaryKey: PrimaryKeyType, completion: #escaping DataApiHandler<ReturnType>)
}
class RealmAccessStrategy: DataApiAccess {
...
// Typealias
internal typealias ReturnType = Object
func read(primaryKey: Any, completion: #escaping ((DataResult<Object>) -> Void)) {
guard let realmObject = realmInstance.object(ofType: realmObjectType, forPrimaryKey: primaryKey) else {
completion(.failure(RealmAccessError.noObject))
return
}
completion(.success(realmObject))
}
}
class PersistenceController {
private let strategy: DataApiAccess // ERROR: Protocol 'DataApiAccess' can only be used as a generic constraint because it has Self or associated type requirements
init(use: DataApiAccess) {
self.strategy = use
}
...
}
}
🆘 ERROR: Protocol 'DataApiAccess' can only be used as a generic constraint because it has Self or associated type requirements
You cannot set variable generic protocols but you can set methods
Example code below
Create enum for base result:
enum DataResult<T> {
case success(T)
case failure(Error)
}
///Set a protocol generic methods:
protocol DataApiAccess {
func read<T: Codable>(primaryKey: PrimaryKeyType, completion: #escaping (DataResult<T>) -> Void)
}
class RealmAccessStrategy: DataApiAccess {
func read<T: Codable>(primaryKey: PrimaryKeyType, completion: #escaping (DataResult<T>) -> Void) {
// Read data from database
}
}
class NetworkAccessStrategy: DataApiAccess {
func read<T: Codable>(primaryKey: PrimaryKeyType, completion: #escaping (DataResult<T>) -> Void) {
// Get data from request
}
}
class PersistenceController {
private let strategy: DataApiAccess
init(use: DataApiAccess) {
// Set dependency inversion for offline or online state
self.strategy = use
}
func foo() {
// TODO
//strategy.read(primaryKey: <#T##PrimaryKeyType#>, completion: <#T##(DataResult<Decodable & Encodable>) -> Void#>)
}
}
Enjoy!
I have a generic protocol, TwoWayBindDelegate, that uses the generic associated type to determine the parameters of the function twoWayBind()
protocol TwoWayBindDelegate: class {
associatedtype BindType
func twoWayBind(to observable: Observable<BindType>?, observableChanged: ((BindType) -> ())?)
}
I then created a class, Reactive<Base: UIView, Type> (which conforms to TwoWayBindDelegate) where you have to initialize it with the generic Base. For eg: let reactiveSlider = Reacive<UISlider>(slider).
My issue is when I am extending Reactive and conforming to TwoWayBindDelegate, I get an error Invalid redeclaration of 'BindType' because I am declaring BindType and twoWayBind() in both my extensions. Is there a way I can have both extensions provide different implementations for TwoWayBindDelegate
class Reactive<Base: UIView>: TwoWayBindDelegate {
public var base: Base
init(base: Base) {
self.base = base
}
}
extension Reactive where Base == UISlider {
typealias BindType = Float
func twoWayBind(to observable: Observable<Float>?, observableChanged: ((Float) -> ())?) {
// implement two way bind for UISlider
}
}
extension Reactive where Base == UITextField {
typealias BindType = String
func twoWayBind(to observable: Observable<String>?, observableChanged: ((String) -> ())?) {
// implement two way bind for UITextField
}
}
I did some research and found out that it may be a bug https://bugs.swift.org/browse/SR-5392. Does there happen to be a workaround
I don't quite see what the typealias is for. The function declaration alone is sufficient to tell the compiler what BindType must be.
The problem I found with your code (apart from the missing Observable declaration, of course) is that the Reactive class itself doesn't conform to TwoWayBindDelegate. To get around that, I threw in an arbitrary implementation of twoWayBind. When I did, and when I deleted the unnecessary typealias declarations, your code compiled for me:
struct Observable<T> {}
protocol TwoWayBindDelegate: class {
associatedtype BindType
func twoWayBind(to observable: Observable<BindType>?, observableChanged: ((BindType) -> ())?)
}
class Reactive<Base: UIView>: TwoWayBindDelegate {
public var base: Base
init(base: Base) {
self.base = base
}
func twoWayBind(to observable: Observable<Int>?, observableChanged: ((Int) -> ())?) {
}
}
extension Reactive where Base == UISlider {
func twoWayBind(to observable: Observable<Float>?, observableChanged: ((Float) -> ())?) {
}
}
extension Reactive where Base == UITextField {
func twoWayBind(to observable: Observable<String>?, observableChanged: ((String) -> ())?) {
}
}
I wonder is that possible to create a protocol, in which its method refer to a type for the conforming class
UHSyncObjectProtocol Protocol
protocol UHSyncObjectProtocol: class {
func sync(completionBlock: ((UHSyncObjectProtocol) -> Void)?)
// ideally, I want to refer to the conforming class instead of UHSyncObjectProtocol
}
User Profile Class
class UHUserProfile: UHSyncObjectProtocol {
func sync(completionBlock: ((UHUserProfile) -> Void)?) {
// do something
completionBlock?(self)
}
}
User Account Class
class UHUserAccount: UHSyncObjectProtocol {
func sync(completionBlock: ((UHUserAccount) -> Void)?) {
// do something
completionBlock?(self)
}
}
I'm not sure it's possible or not.
You can use generics to achieve that
Here is example
protocol UHSyncObjectProtocol: class {
associatedtype T
func sync(completionBlock: ((T) -> Void)?)
// ideally, I want to refer to the conforming class instead of UHSyncObjectProtocol
}
class UHUserProfile: UHSyncObjectProtocol {
func sync(completionBlock: ((UHUserProfile) -> Void)?) {
// do something
completionBlock?(self)
}
}
class UHUserAccount: UHSyncObjectProtocol {
func sync(completionBlock: ((UHUserAccount) -> Void)?) {
// do something
completionBlock?(self)
}
}
I am having a Protocol implementation as follows.
protocol DatabaseInjectable {
static func deriveObjectFromDBRow(row: [String]) -> Self? // Method - 1
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [Self]? // Method - 2
}
Where I am successful with the correspondent implementation of Method - 1 like this:
static func deriveObjectFromDBRow(row: [String]) -> Self? {
...
}
But I could not implement the Method - 2 like this:
static func collectAllObjectsForDatabaseAction(action: (WWDatabase) -> Void) -> [Self]? {
...
}
There I am getting an error like this:
'Self' is only available in a protocol or as the result of a method in a class;
Any help to return the array form of Self (the class it self) would be nice.
If you can set your class final you can replace Self by the class name
final class SampleClass: DatabaseInjectable {
init() {
}
static func deriveObjectFromDBRow(row: [String]) -> SampleClass? {
return SampleClass()
}
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [SampleClass]? {
let array = [SampleClass]()
return array
}
}
There's a very well written answer here, but in short, you can define your protocol as such:
protocol DatabaseInjectable {
static func deriveObjectFromDBRow(row: [String]) -> DatabaseInjectable? // Method - 1
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [DatabaseInjectable]? // Method - 2
}
You can make use of a typealias in your protocol DatabaseInjectable, and use this as an alias to Self type in the classes conforming to your protocol.
class Database {
var desc : String = "Default"
}
protocol DatabaseInjectable {
typealias MySelf
static func deriveObjectFromDBRow(row: [String]) -> MySelf?
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [MySelf]?
}
class MyClass : DatabaseInjectable {
typealias MySelf = MyClass
static func deriveObjectFromDBRow(row: [String]) -> MySelf? {
return MyClass()
}
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [MySelf]? {
return [MyClass(), MyClass()]
}
}
/* example */
let closure : (Database) -> () = { print($0.desc) }
var arr : [MyClass]? = MyClass.collectAllObjectsForDatabaseAction(closure)
/* [MyClass, MyClass] */
One drawback here is, however, that you could set e.g. typealias MySelf = Int (in the class) and have your functions return an integer/array of integers (rather than self/[Self]), and still conform to you protocol. Possibly this is a deal-breaker.