Unable to infer closure type in the current context in APIClient - swift

I'm trying to migrate code from Swift 3.2 to Swift 4.2. When put in Xcode 10.1 I get this error.'Unable to infer closure type in the current context '. This is using YALAPIClient. Please help.
Unable to infer closure type in the current context
This I found on stack overflow. But I'm not using any try method here.Please help.
private func presentIndustrySearch() {
let dataProvider = RequestDataProvider { return IndustriesRequest() } /*error comes here*/
}
public class RequestDataProvider<Representation, Request>: DataProvider, NetworkClientInjectable
where
Request: SerializeableAPIRequest,
Request.Parser.Representation == [Representation]
{
public typealias Item = Representation
public typealias RequestConstructor = () -> Request
public private(set) var data = [Item]()
private let requestConstructor: RequestConstructor
public init(_ requestConstructor: #escaping RequestConstructor) {
self.requestConstructor = requestConstructor
}
public func loadData(before: () -> Void, after: #escaping (Error?) -> Void) {
let request: Request = self.requestConstructor()
before()
networkClient.execute(request: request, parser: request.parser, completion: { [weak self] task in
guard let `self` = self else { return }
if let data = task.value, data.count != 0 {
self.data.append(contentsOf: data)
after(nil)
} else if let error = task.error {
after(error as NSError)
} else {
let error = NSError.reachedEndOfPage()
after(error)
}
})
}
}
public protocol SerializeableAPIRequest: APIRequest {
associatedtype Parser: ResponseParser
var parser: Parser { get }
}
public struct IndustriesRequest: SerializeableAPIRequest, TokenizedAPIRequest, StubAPIRequest {
public private(set) var method = APIRequestMethod.get
public private(set) var path = "industries"
public private(set) var parser = KeyPathMappableArrayParser<[Industry]>(keyPath: "data")
public private(set) var parameters: [String: String]? = [:]
public private(set) var authenticationTokenRequired = true
public init(value: String = "") {
parameters!["term"] = value
}
}

Related

Getting "Must have a uuid if no _objectID" exception when inserting object into dictionary

I'm writing a unit-test to a class that uses PHAsset type. I mocked it as below:
class PHAssetMock: PHAsset {
let date: Date
let uuid: UUID
init(dateStr: String) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy HH:mm"
self.date = dateFormatter.date(from: dateStr)!
self.uuid = UUID()
}
override var creationDate: Date? {
return date
}
override var hash: Int {
let hash = Int(self.date.timeIntervalSinceNow)
return hash
}
static func ==(lhs: PHAsseMock, rhs: PHAsseMock) -> Bool {
return lhs.date.timeIntervalSinceNow == rhs.date.timeIntervalSinceNow
}
}
When a function that uses mocked objects tries to insert it in a dictionary I'm getting an exception:
func foo(assets: [PHAsset]) {
var label: [T: String]()
for asset in assets {
label[asset] = "undefined" // Exception: "NSInternalInconsistencyException", "Must have a uuid if no _objectID"
}
}
When debugging, the override hash var is being called.
I had the same issue with the PHAsset when unit testing Photos framework. Overriding isEqual function helped to get rid of the exception.
class Mock : PHAsset {
let _localIdentifier: String = UUID().uuidString
let _hash: Int = UUID().hashValue
override var localIdentifier: String {
return _localIdentifier
}
override var hash: Int {
return _hash
}
override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? Mock else {
return false
}
return self.localIdentifier == object.localIdentifier
}
}

Make ObservableObject subscribe to custom PropertyWrapper

I have written a custom PropertyWrapper, that tries to wrap UserDefaults while also giving them the same behaviour as a #Published variable. It almost works, except that the ObservableObject does not propagate the changes without observing the UserDefaults themselves.
I cannot pass a objectWillChange ref to the #Setting init, as self is not available during Settings.init...
I wonder how #Published does that..
import Combine
import Foundation
class Settings: ObservableObject {
// Trying to avoid this:
/////////////////////////////////////////////
let objectWillChange = PassthroughSubject<Void, Never>()
private var didChangeCancellable: AnyCancellable?
private init(){
didChangeCancellable = NotificationCenter.default
.publisher(for: UserDefaults.didChangeNotification)
.map { _ in () }
.receive(on: DispatchQueue.main)
.subscribe(objectWillChange)
}
/////////////////////////////////////
static var shared = Settings()
#Setting(key: "isBla") var isBla = true
}
#propertyWrapper
public struct Setting<T> {
let key: String
let defaultValue: T
init(wrappedValue value: T, key: String) {
self.key = key
self.defaultValue = value
}
public var wrappedValue: T {
get {
let val = UserDefaults.standard.object(forKey: key) as? T
return val ?? defaultValue
}
set {
objectWillChange?.send()
publisher?.subject.value = newValue
UserDefaults.standard.set(newValue, forKey: key)
}
}
public struct Publisher: Combine.Publisher {
public typealias Output = T
public typealias Failure = Never
public func receive<Downstream: Subscriber>(subscriber: Downstream)
where Downstream.Input == T, Downstream.Failure == Never {
subject.subscribe(subscriber)
}
fileprivate let subject: Combine.CurrentValueSubject<T, Never>
fileprivate init(_ output: Output) {
subject = .init(output)
}
}
private var publisher: Publisher?
internal var objectWillChange: ObservableObjectPublisher?
public var projectedValue: Publisher {
mutating get {
if let publisher = publisher {
return publisher
}
let publisher = Publisher(wrappedValue)
self.publisher = publisher
return publisher
}
}
}

swift - UserDefaults wrapper

I want to make userDefaults easier to use. I write this code.
But I don't want to create a allKeys enum(cases voipToken, userId, userName, displayName,...) as the key path for my property.
If I want add a var accessToken to struct LoginInfo, I must add a case accessToken to enum AllKeys. I use CoreStore.key(.accessToken) get a keyPath for CoreStore.LoginInfo.accessToken.
import Foundation
struct CoreStore {
// static let sharedInstance = CoreStore()
// private init(){}
private static let keyPrefix = "_shared_store_"
enum allKeys: String {
case accessToken
}
static func key(_ key: allKeys) -> String {
return keyPrefix + key.rawValue
}
struct LoginInfo: CoreStoreSettable,CoreStoreGettable { }
}
extension CoreStore.LoginInfo {
static var accessToken: String? {
set {
set(value: newValue, forKey: CoreStore.key(.accessToken))
}
get {
return getString(forKey: CoreStore.key(.accessToken))
}
}
// ...
}
protocol CoreStoreSettable {}
extension CoreStoreSettable {
static func set(value: String?, forKey key: String) {
UserDefaults.standard.set(value, forKey: key)
}
}
protocol CoreStoreGettable {}
extension CoreStoreGettable {
static func getString(forKey key: String) -> String? {
return UserDefaults.standard.string(forKey: key)
}
}
Questions:
Is there a way to remove "enum allKeys"?
Should I use sharedInstance? Why?
I tried :
static var accessToken: String? {
set {
let keyPath = \CoreStore.Loginfo.accessToken
let keyPathString = keyPath.string
set(value: newValue, forKey: keyPathString)
}
get {
return getString(forKey: CoreStore.key(.accessToken))
}
}
I get error "Type of expression is ambiguous without more context"

How to overcome the error of "Generic parameter 'T' is not used in function signature"?

I'm trying to convert the following to be generic.
extension RLMOrganization: DataProvider {
func getLastSyncToken() -> String {
let lastUpdated: RLMOrganization? = self.findAll(sortedBy: "syncToken").last
if let syncToken = lastUpdated?.syncToken {
return syncToken
} else {
return "00000000000000000000000000000000"
}
}
}
And have tried this:
protocol DataProvider: DatabaseLayer {
associatedtype T: Object
func findAll<T: Object>(sortedBy key: String) -> [T]
}
extension DataProvider {
func findAll<T: Object>(sortedBy key: String) -> [T] {
let database = self.getDatabase()
if let allObjects = database?.objects(T.self) {
let results = allObjects.sorted(byKeyPath: key, ascending: true)
return Array(results)
}
return []
}
func getLastSyncToken<T: Object>() -> String {
let lastUpdated = self.findAll(sortedBy: "syncToken").last as? T
if let value = lastUpdated?.value(forKey: "syncToken") { // get value from object by string name
let syncToken = value as! String
return syncToken
} else {
return "00000000000000000000000000000000"
}
}
...
But can't seem to overcome the error of:
Generic parameter 'T' is not used in function signature
I would think the compiler has everything it needs to determine type usage.
Below works for me, I don't know how findAll is defined but the problem is the reference to self as I see it so you need to define T there using associatedtype.
protocol DataProvider: DatabaseLayer {
associatedtype T: Object
func findAll(sortedBy: String) -> T?
}

Use of unresolved identifier 'Singleton' Swift 3

Here is my below code:
private static var __once: () = {
Singleton.instance = RtccManager()
if let instance = Singleton.instance {
instance.connectionParameters = instance.flattenConnectionParametersOverride(nil)
instance.currentStat = .sta_notConnected
DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.background).async {
instance.rtccConnect([:])
}
}
}()
var connectionParameters: [String : Any] = [:]
var currentStat: AppStatus = AppStatus.sta_notConnected
class var sharedInstance: RtccManager {
struct Singleton {
static var instance: RtccManager? = nil
static var token: Int = 0
}
_ = RtccManager.__once
return Singleton.instance!
}
I am getting error on line Singleton.instance = RtccManager() and line
if let instance = Singleton.instance
Error is: Use of unresolved identifier 'Singleton'
This error came after migrating to Swift 3.0
Any ideas on how can I resolve this error's?
If you're migrating your code It's should be a good idea to adapt your singleton creation mode to the new way suggested by Apple in their docs.
Here's an example
public class RtccManager
{
/*
Nested types
*/
public enum AppStatus
{
case sta_connected
case sta_notConnected
}
public static let sharedInstance: RtccManager = RtccManager()
public private(set) var connectionParameters: [String: Any]
public private(set) var currentStat: AppStatus
private init()
{
self.connectionParameters = [String: Any]()
// flattenConnectionParametersOverride
self.currentStat = .sta_notConnected
}
}