Could not infer generic parameter when calling protocol static method - swift

Using a Playground and given these definitions:
import Foundation
protocol MoneyTrakObject {
var key: String { get set }
init()
}
extension MoneyTrakObject {
static func objectFromDB<T: MoneyTrakObject>(for key: String, queue: DispatchQueue? = nil, completion: #escaping (T) -> Void) -> String? {
// after data is retrieved, call completion closure
let valueObject = T()
completion(valueObject)
return "dbToken"
}
}
protocol Transaction: MoneyTrakObject {
var amount: Int { get set }
}
struct BasicTransaction: Transaction {
var key = UUID().uuidString
var amount = 0
init() {}
}
struct RecurringTransaction: Transaction {
var key = UUID().uuidString
var amount = 0
init() {}
}
I would expect that I could do this:
let token1 = BasicTransaction.objectFromDB(for: "") { (transaction) in
// use transaction
}
let token2 = RecurringTransaction.objectFromDB(for: "") { (transaction) in
// use transaction
}
However I get the Generic parameter 'T' could not be inferred error when calling the static method and I'm not sure why.

I do not see why you need the generic constraint. If you change the extension of your protocol to this:
extension MoneyTrakObject {
static func objectFromDB(for key: String, queue: DispatchQueue? = nil, completion: #escaping (Self) -> Void) -> String? {
// after data is retrieved, call completion closure
let valueObject = Self()
completion(valueObject)
return "dbToken"
}
}
Your code compiles just fine. Self is a placeholder for the actually implementing type.

Well... the only place where T is used is inside the completion handler argument. When you write this:
let token1 = BasicTransaction.objectFromDB(for: "") { (transaction) in
// use transaction
}
The compiler has no idea what type transaction is and hence cannot specialize the generic function. Provide some type info like this:
let token1 = BasicTransaction.objectFromDB(for: "") { (transaction: Transaction) in
// use transaction
}
let token2 = BasicTransaction.objectFromDB(for: "") { (transaction: BasicTransaction) in
// use transaction
}

Related

I need to edit the generic class Swift

I need to change this generic class that accepts an array to something that is not an array
class GenericDataSource<T> : NSObject {
var data: DynamicValue<[T]> = DynamicValue([])
//var data: DynamicValue<T>?
}
When I remove the square brackets I get an error
typealias CompletionHandler = (() -> Void)
class DynamicValue<T> {
var value : T {
didSet {
self.notify()
}
}
private var observers = [String: CompletionHandler]()
init(_ value: T) {
self.value = value
}
public func addObserver(_ observer: NSObject, completionHandler: #escaping CompletionHandler) {
observers[observer.description] = completionHandler
}
public func addAndNotify(observer: NSObject, completionHandler: #escaping CompletionHandler) {
self.addObserver(observer, completionHandler: completionHandler)
self.notify()
}
private func notify() {
observers.forEach({ $0.value() })
}
deinit {
observers.removeAll()
}
}
You need an init in GenericDataSource
class GenericDataSource<T> {
var data: DynamicValue<T>
init(_ value: T) {
data = DynamicValue(value)
}
}
or make data optional
class GenericDataSource<T> : NSObject {
var data: DynamicValue<T>?
}
And then use them like
let gds = GenericDataSource("Hello")
or for the optional variant
let gds = GenericDataSource<String>()
gds.data = DynamicValue("Hello")

Can a Swift Property Wrapper reference the owner of the property its wrapping?

From within a property wrapper in Swift, can you someone refer back to the instance of the class or struck that owns the property being wrapped? Using self doesn't obviously work, nor does super.
I tried to pass in self to the property wrapper's init() but that doesn't work either because self on Configuration is not yet defined when #propertywrapper is evaluated.
My use case is in a class for managing a large number of settings or configurations. If any property is changed, I just want to notify interested parties that something changed. They don't really need to know which value just, so use something like KVO or a Publisher for each property isn't really necessary.
A property wrapper looks ideal, but I can't figure out how to pass in some sort of reference to the owning instance that the wrapper can call back to.
References:
SE-0258
enum PropertyIdentifier {
case backgroundColor
case textColor
}
#propertyWrapper
struct Recorded<T> {
let identifier:PropertyIdentifier
var _value: T
init(_ identifier:PropertyIdentifier, defaultValue: T) {
self.identifier = identifier
self._value = defaultValue
}
var value: T {
get { _value }
set {
_value = newValue
// How to callback to Configuration.propertyWasSet()?
//
// [self/super/...].propertyWasSet(identifier)
}
}
}
struct Configuration {
#Recorded(.backgroundColor, defaultValue:NSColor.white)
var backgroundColor:NSColor
#Recorded(.textColor, defaultValue:NSColor.black)
var textColor:NSColor
func propertyWasSet(_ identifier:PropertyIdentifier) {
// Do something...
}
}
The answer is no, it's not possible with the current specification.
I wanted to do something similar. The best I could come up with was to use reflection in a function at the end of init(...). At least this way you can annotate your types and only add a single function call in init().
fileprivate protocol BindableObjectPropertySettable {
var didSet: () -> Void { get set }
}
#propertyDelegate
class BindableObjectProperty<T>: BindableObjectPropertySettable {
var value: T {
didSet {
self.didSet()
}
}
var didSet: () -> Void = { }
init(initialValue: T) {
self.value = initialValue
}
}
extension BindableObject {
// Call this at the end of init() after calling super
func bindProperties(_ didSet: #escaping () -> Void) {
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if var child = child.value as? BindableObjectPropertySettable {
child.didSet = didSet
}
}
}
}
You cannot do this out of the box currently.
However, the proposal you refer to discusses this as a future direction in the latest version:
https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md#referencing-the-enclosing-self-in-a-wrapper-type
For now, you would be able to use a projectedValue to assign self to.
You could then use that to trigger some action after setting the wrappedValue.
As an example:
import Foundation
#propertyWrapper
class Wrapper {
let name : String
var value = 0
weak var owner : Owner?
init(_ name: String) {
self.name = name
}
var wrappedValue : Int {
get { value }
set {
value = 0
owner?.wrapperDidSet(name: name)
}
}
var projectedValue : Wrapper {
self
}
}
class Owner {
#Wrapper("a") var a : Int
#Wrapper("b") var b : Int
init() {
$a.owner = self
$b.owner = self
}
func wrapperDidSet(name: String) {
print("WrapperDidSet(\(name))")
}
}
var owner = Owner()
owner.a = 4 // Prints: WrapperDidSet(a)
My experiments based on : https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md#referencing-the-enclosing-self-in-a-wrapper-type
protocol Observer: AnyObject {
func observableValueDidChange<T>(newValue: T)
}
#propertyWrapper
public struct Observable<T: Equatable> {
public var stored: T
weak var observer: Observer?
init(wrappedValue: T, observer: Observer?) {
self.stored = wrappedValue
}
public var wrappedValue: T {
get { return stored }
set {
if newValue != stored {
observer?.observableValueDidChange(newValue: newValue)
}
stored = newValue
}
}
}
class testClass: Observer {
#Observable(observer: nil) var some: Int = 2
func observableValueDidChange<T>(newValue: T) {
print("lol")
}
init(){
_some.observer = self
}
}
let a = testClass()
a.some = 4
a.some = 6
The answer is yes! See this answer
Example code for calling ObservableObject publisher with a UserDefaults wrapper:
import Combine
import Foundation
class LocalSettings: ObservableObject {
static var shared = LocalSettings()
#Setting(key: "TabSelection")
var tabSelection: Int = 0
}
#propertyWrapper
struct Setting<T> {
private let key: String
private let defaultValue: T
init(wrappedValue value: T, key: String) {
self.key = key
self.defaultValue = value
}
var wrappedValue: T {
get {
UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
public static subscript<EnclosingSelf: ObservableObject>(
_enclosingInstance object: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, T>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Setting<T>>
) -> T {
get {
return object[keyPath: storageKeyPath].wrappedValue
}
set {
(object.objectWillChange as? ObservableObjectPublisher)?.send()
UserDefaults.standard.set(newValue, forKey: object[keyPath: storageKeyPath].key)
}
}
}

How to chain functions with a completion handler in Swift?

I am chaining some functions together and I can't figure out how to call a completion handler with a return value once all the functions are done running.
func getAirQuality(completion: (aqi: Int?) -> Void) {
callAPI()
}
private func callAPI() {
// ... get data
self.parseDataForAQI(data: data)
}
private func parseDataForAQI(data: Data) {
let aqi = aqi
// Send aqi up to completion handler in getAirQuality
}
So that when everything is said and done I can just do something like this:
getAirQuality(completion: { aqi -> Void in {
// Do something with aqi
})
My first assumption is that your first 3 functions are part of a class. If so, one approach is to save the completion handler as an instance variable.
class AirQualityProvider {
var aBlock: ((Int?) -> Void)?
func getAirQuality(completion: #escaping (Int?) -> Void) {
aBlock = completion
callAPI()
}
private func callAPI() {
let data = Data()
parseDataForAQI(data: data)
}
private func parseDataForAQI(data: Data) {
let aqi = 1
if let completion = aBlock {
completion(aqi)
}
}
}
Here's an example of a caller as written in a playground.
let aqp = AirQualityProvider()
aqp.getAirQuality { (value) in
if let value = value {
print("Value = \(value)")
}
}

Extract self-properties in block-method

I have some trouble in understanding my specific request, in Swift.
There is a class named Origin and multiple its subclasses.
How I can update my block-method written ONLY in Origin class?
class Origin: NSObject {
func mod(_ block: (() throws -> Void)) {
try! block()
}
}
I need use mod from all Origin subclasses, and I need to have this usage effect:
var originSubclassObject = OriginSubclass()
originSubclassObject.mod {
.age = 12 //age is OriginSubclass property
.name = "Bob" //name is OriginSubclass property
}
So, you see, I need extract OriginSubclass properties for using in mod-block. I need to create usage exactly likes in usage effect code (extract mod-caller properties from ".").
Thanks all for help!
You could consider a protocol with a default implementation, e.g.:
protocol Modifiable { }
extension Modifiable {
func mod(_ block: ((Self) throws -> Void)) {
try! block(self)
}
}
class Origin: Modifiable { }
class OriginSubclass: Origin {
var name: String?
var age: Int?
}
And then:
let originSubclassObject = OriginSubclass()
originSubclassObject.mod { object in
object.age = 12
object.name = "Bob"
}
Or
let originSubclassObject = OriginSubclass()
originSubclassObject.mod {
$0.age = 12
$0.name = "Bob"
}
Or, if that base class was only there for the mod method, you could lose it entirely:
protocol Modifiable { }
extension Modifiable {
func mod(_ block: ((Self) throws -> Void)) {
try! block(self)
}
}
class MyObject: Modifiable {
var name: String?
var age: Int?
}
And
let myObject = MyObject()
myObject.mod { object in
object.age = 12
object.name = "Bob"
}
Or
let myObject = MyObject()
myObject.mod {
$0.age = 12
$0.name = "Bob"
}

Different process between Struct and Class in mutating asynchronously in Swift3

In struct type, mutating self in async process makes error as below.
closure cannot implicitly captured a mutating self
If I change the struct to class type, the error disappear.
What is difference between struct and class when mutate self in asynchronously?
struct Media {
static let loadedDataNoti = "loadedDataNotification"
let imagePath: String
let originalPath: String
let description: String
var imageData: Data?
let tag: String
var likeCount: Int?
var commentCount: Int?
var username: String?
var delegate: MediaDelegate?
public init(imagePath: String, originalPath: String, description: String, tag: String, imageData: Data? = nil) {
self.imagePath = imagePath
self.originalPath = originalPath
self.description = description
self.tag = tag
if imageData != nil {
self.imageData = imageData
} else {
loadImageData()
}
}
mutating func loadImageData() {
if let url = URL(string: imagePath) {
Data.getDataFromUrl(url: url, completion: { (data, response, error) in
if (error != nil) {
print(error.debugDescription)
return
}
if data != nil {
self.imageData = data! // Error: closure cannot implicitly captured a mutating self
NotificationCenter.default.post(name: NSNotification.Name(rawValue: Media.loadedDataNoti), object: data)
}
})
}
}
A struct is a value type. How does struct mutating work? It works by making a completely new struct and substituting it for the original. Even in a simple case like this:
struct S {
var name = "matt"
}
var s = S()
s.name = "me"
... you are actually replacing one S instance by another — that is exactly why s must be declared as var in order to do this.
Thus, when you capture a struct's self into an asynchronously executed closure and ask to mutate it, you are threatening to appear at some future time and suddenly rip away the existing struct and replace it by another one in the middle of executing this very code. That is an incoherent concept and the compiler rightly stops you. It is incoherent especially because how do you even know that this same self will even exist at that time? An intervening mutation may have destroyed and replaced it.
Thus, this is legal:
struct S {
var name = "matt"
mutating func change() {self.name = "me"}
}
But this is not:
func delay(_ delay:Double, closure:#escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
struct S {
var name = "matt"
mutating func change() {delay(1) {self.name = "me"}} // error
}
When you mutate an instance of a value type -- such as a struct -- you're conceptually replacing it with a new instance of the same type, i.e. doing this:
myMedia.mutatingFuncToLoadImageData()
...can be thought of as doing something like this:
myMedia = Media(withLoadedData: theDownloadedData)
...except you don't see the assignment in code.
You're effectively replacing the instance that you call a mutating function on. In this case myMedia. As you may realize, the mutation has to have finished at the end of the mutating function for this to work, or your instance would keep changing after calling the mutating function.
You're handing off a reference to self to an asynchronous function that will try to mutate your instance after your mutating function has ended.
You could compile your code by doing something like
var myself = self // making a copy of self
let closure = {
myself.myThing = "thing"
}
but that would only change the value of the variable myself, and not affect anything outside of your function.