"withLatestFrom" won't accept BehaviorRelay - swift

I've got this simple view model to check a phone number's status before registering a user. But I've got this error:
Instance method 'withLatestFrom' requires that 'BehaviorRelay' conform to 'SharedSequenceConvertibleType'
Here's the code:
import Foundation
import RxSwift
import RxCocoa
protocol RegisterViewModelling {
var openRegistrationData: Signal<String> { get }
var showErrorMessage: Signal<String> { get }
var sendButtonActive: Driver<Bool> { get }
var phoneNumberText: BehaviorRelay<String> { get }
var tapSendButton: PublishRelay<Void> { get }
}
final class RegisterViewModel: RegisterViewModelling {
var openRegistrationData: Signal<String>
let showErrorMessage: Signal<String>
let sendButtonActive: Driver<Bool>
let phoneNumberText: BehaviorRelay<String> = BehaviorRelay<String>(value: "")
let tapSendButton: PublishRelay<Void> = PublishRelay<Void>()
init(getPhoneNumberStatus: GetPhoneNumberStatusUseCase) {
sendButtonActive = phoneNumberText
.asDriver(onErrorDriveWith: .empty())
.map(shouldButtonActive(number:))
let isRegistered = tapSendButton
.withLatestFrom(phoneNumberText)
.flatMap(getPhoneNumberStatus.get(number:))
.share()
showErrorMessage = isRegistered
.asSignal(onErrorSignalWith: .just(true))
.filter { $0 == true }
.map { _ in () }
.map(getErrorMessage)
openRegistrationData = isRegistered
.asSignal(onErrorSignalWith: .just(true))
.filter { $0 == false }
.withLatestFrom(phoneNumberText) // ERROR: Instance method 'withLatestFrom' requires that 'BehaviorRelay<String>' conform to 'SharedSequenceConvertibleType'
}
}
private func shouldButtonActive(number: String) -> Bool {
return !number.isEmpty && number.count <= 15
}
private func getErrorMessage() -> String {
return "Phone number has been registered."
}
protocol GetPhoneNumberStatusUseCase {
func get(number: String) -> Observable<Bool>
}
What went wrong here? Why won't withLatestFrom work at that line but it worked fine on the others? Thanks.

I think it because you have convert isRegistered to Signal before use withLatestFrom. You can try to move asSignal() to below withLatestFrom

Related

Storing Generic Objects in a Heterogeneous Array and retrieving object parameter as the correct type

Ahoy everyone,
I have recently been trying to implement a Node based graph system that passes data between nodes using plugs. Similar to many of the 3D applications like houdini and maya.
I have written a similar system before using Python, and wanted to try this with Swift as my first learning excersise. Boy did I jump into the deep end on this one.
I am stuck now with Swifts Arrays, as I would like to store a list of Generic plugs.
Each plug can have its own value type float, int, color, string, Vector Matrix.
I have read up about Type Erasers and opaque types, but still cant seem to get my values our of a list in a way that I can perform some arithmetic on them.
All and any help that might put me in the direction would be greatly appreciated :D
import Foundation
import MetalKit
protocol genericPlug {
associatedtype T
func GetValue() -> T
}
class Plug<T>:genericPlug{
var _value:T?
var value:T {
get{GetValue()}
set(val){
value = val
}
}
func GetValue() -> T{
return _value!
}
init(_ newValue:T){
_value=newValue
}
}
class Node{
var plugs:[genericPlug] = []
init(){
var p1 = Plug<Int>(0)
var p2 = Plug(vector2(1.2, 3.1))
var p3 = Plug([0.0, 3.1, 0.6, 1])
plugs.append(p1)
plugs.append(p2)
plugs.append(p3)
}
func execute(){
// will access the plugs in the array and perform some sort of calculations on them.
plugs[0].value + 1 // should equal 1
plugs[1].value.x + 0.8 // should have x=2.0 y=3.1
plugs[2].value[1] - 0.1 // should equal 3.0
}
}
Thanks everyone
Use a generic something to extract what you need. Your options are methods and subscripts.
protocol PlugValue {
init()
}
extension Int: PlugValue { }
extension Float: PlugValue { }
extension Double: PlugValue { }
extension SIMD3: PlugValue where Scalar == Int32 { }
struct Plug<Value: PlugValue> {
var value: Value
init(_ value: Value) {
self.value = value
}
}
protocol AnyPlug {
var anyValue: PlugValue { get }
}
extension AnyPlug {
subscript<Value: PlugValue>(type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
func callAsFunction<Value: PlugValue>(_ type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
}
extension Plug: AnyPlug {
var anyValue: PlugValue { value }
}
let plugs: [AnyPlug] = [
Plug(1),
Plug(2.3 as Float),
Plug(4.5),
Plug([6, 7, 8] as SIMD3)
]
plugs[0][Int.self] // 1
plugs[1][Double.self] // 0
plugs[1][] as Float // 2.3
let double: Double = plugs[2]() // 4.5
plugs[3](SIMD3.self).y // 7
With the array of protocols, do you have to down cast them into their Plug when retrieving them every time?
Essentially. This is true of all heterogenous sequences. Here are your options:
extension Array: PlugValue where Element: PlugValue { }
let plug: AnyPlug = Plug([0.1, 1.1, 2.1])
(plug as? Plug<[Double]>)?.value[1]
(plug.anyValue as? [Double])?[1]
extension Plug {
enum Error: Swift.Error {
case typeMismatch
}
}
extension AnyPlug {
func callAsFunction<Value: PlugValue, Return>(_ closure: (Value) -> Return) throws {
guard let value = anyValue as? Value
else { throw Plug<Value>.Error.typeMismatch }
closure(value)
}
}
try plug { (doubles: [Double]) in doubles[1] } // 1.1
try plug { ($0 as [Double])[1] } // 1.1
try plug { $0 as Int } // <Swift.Int>.Error.typeMismatch
I managed to find a solution that worked for my needs.
I am still looking at finding a better way to handle getting the data and their correct type.
import Foundation
import MetalKit
// Creating the PlugType Enum
enum PlugType{
case Integer(Int?)
case Float_(Float?)
case Double_(Double?)
case Vector3(simd_int3)
// default types
static func IntegerType() -> PlugType{ return PlugType.Integer(nil)}
static func FloatType() -> PlugType{ return PlugType.Float_(nil)}
static func DoubleType() -> PlugType{ return PlugType.Double_(nil)}
}
// Implements a way to retrieve the correct value type
extension PlugType{
var IntegerValue: Int{
switch self{
case .Integer(let value):
return value ?? 0
default:
return 0
}
}
var FloatValue: Float{
switch self
{
case .Float_(let value):
return value ?? 0
default:
return 0
}
}
var DoubleValue: Double{
switch self
{
case .Double_(let value):
return value ?? 0
default:
return 0
}
}
}
// Get the string representation of the PlugType
extension PlugType {
var typeName: String{
switch self {
case .Integer: return "Integer"
case .Float_: return "Float"
case .Double_: return "Double"
case .Vector3: return "Vector3"
}
}
var swiftType: Any.Type {
switch self {
case .Integer: return Int.self
case .Float_: return Float.self
case .Double_: return Double.self
case .Vector3: return simd_int3.self
}
}
}
class Plug{
var _value:PlugType?
var type:String? { get{ return _value?.typeName } }
init(_ newValue:PlugType){
_value = newValue
}
func geee<T>(_ input:T) -> T{
switch type {
case "Integer":
return getVal(_value!.IntegerValue) as! T
case "Double":
return getVal(_value!.DoubleValue) as! T
default:
return 0 as! T
}
}
func getVal(_ val:Int) -> Int {
return val
}
func getVal(_ val:Float) -> Float {
return val
}
func getVal(_ val:Double) -> Double {
return val
}
}
var plugs:[Plug] = []
var p1 = Plug(PlugType.Integer(2))

How to merge nil cases to Failing case

import MVVMC
import RxSwift
import RxCocoa
import RTVModel
import RTVWebAPI
public class SettingsViewModel: ViewModel {
public var fetchedNotifications: Driver<[NotificationItem]> = .empty()
public var fetchedNotificationsFailed: Driver<String> = .empty()
public var notificationCount: Driver<Int> = .empty()
'''''''''''''''
public var userLoginName: Driver<String> = .empty()
///// userLoginName getting is a optional String.
'''''''''''''''''
public var fetchedUserLoginNameFailed: Driver<String> = .empty()
public func bindNotificationEvents(with trigger: Driver<Void>) {
let webService: Driver<RTVInformationListWebService> = trigger
.map { RTVInformationListParameters() }
.webService()
let result = webService.request()
notificationCount = result.success().map { $0.informationList.maxCount }
fetchedNotifications = result.success()
.map {$0.informationList.notifications}
-------> .map {$0.map {NotificationItem.init(notification: $0)}}
///////////////////////////////////////////////////////////////
Error (Value of optional type 'String?' must be unwrapped to a value of type 'String')
///////////////////////////////////////////////////////////////
fetchedNotificationsFailed = Driver.merge(fetchedNotificationsFailed, result.error().map { $0.message })
}
public func bindUserInfoEvents(with trigger: Driver<Void>) {
let webService: Driver<RTVMobileMenuWebService> = trigger
.map { RTVMobileMenuParameters() }
.webService()
let result = webService.request()
userLoginName = result.success().map { ($0.mobileMenuInfo.username) }
fetchedUserLoginNameFailed = Driver.merge(fetchedUserLoginNameFailed, result.error().map { $0.message })
}
}
extension RTVAPIError {
fileprivate var message: String {
var message = "\(self.localizedDescription)"
if let codeNumber = self.codeNumber {
message += "\n(\(codeNumber))"
}
return message
}
}
This is not really the way you should be using it, since the point of Driver is not to error, but you obviously have an error state, therefore, Observable or Signal would be better.
However, you need to split your signal into successful ones and error ones, something like this:
fetchedNotifications = result.success()
.map {$0.informationList.notifications}
.share(replay: 1)
let success = fetchedNotifications
.filter { $0 != nil }
.map { $0.map { NotificationItem.init(notification: $0) } }
let error = fetchedNotifications
.filter { $0 == nil } // Here would be your "error" state which you can merge later
I might be off with the syntax, I wrote this from memory.
I fixed it by using the catchOnNil
.catchOnNil { return }

How to have Error Type inference for a throwing function in a protocol

Is there a way to create a throwing function with a specified Error sub type that will be thrown? Below code is an example of how I'd like it to be.
protocol ValidatorError: Error {
var somePrintableThingy: String { get }
}
protocol Validator {
associatedType T
var model: T { get set }
init(model: T)
func validate() throws where Error: ValidatorError
}
Example Use Case
class SomeModelErrorNotValidatorError: Error {
case invalidUsername
}
class SomeModelError: ValidatorError {
case invalidUsername
var somePrintableThingy: String {
switch self { case .invalidUsername: return "haha" }
}
}
class SomeModel {
var username: String = ""
init(username: String) { self.username = username }
}
class SomeModelValidator: Validator {
var model: SomeModel
init(model: SomeModel) { self.model = model }
func validate() throws {
guard self.model.username.isEmpty else {
// this line should be fine
throw SomeModelError.invalidUsername
// if i replace it with this line it should not be fine
throw SomeModelErrorNotValidatorError.invalidUsername
}
}
}
class SomeModelViewController: UIViewController {
// .. some other codes here
func buttonClicked(_ sender: Any? = nil) {
let model = SomeModel(username: self.txtUsername.text ?? "")
let validator = SomeModelValidator(model: model)
do {
try validator.validate()
} catch let error {
// since I already know that this is a `SomeModelError`
// I could just do this
print(error.somePrintableThingy)
}
}
}
PS: The possible workaround for this is to create a non throwing function with a callback but I don't want to do that
PS PS: Another possible workaround for this would be to use a linting tool, but that's too much.

Hashing problems using a wrapper class around NSUUID as the key

** REWRITE **
OK, it turns out I'm really asking a different question. I understand about hashValue and ==, so that's not relevant.
I would like my wrapper class BUUID to "do the right thing" and act just like NSUUID's act in a Dictionary.
See below, where they don't.
import Foundation
class BUUID: NSObject {
init?(str: String) {
if let uuid = NSUUID(UUIDString: str) {
_realUUID = uuid
}
else {
return nil
}
}
override init() {
_realUUID = NSUUID()
}
private var _realUUID: NSUUID
override var description: String { get { return _realUUID.UUIDString } }
override var hashValue: Int { get { return _realUUID.hashValue } }
var UUIDString: String { get { print("WARNING Use description or .str instead"); return _realUUID.UUIDString } }
var str: String { get { return _realUUID.UUIDString } }
}
func ==(lhs: BUUID, rhs: BUUID) -> Bool { return lhs._realUUID == rhs._realUUID }
let a = BUUID()
let b = BUUID(str: a.str)!
print("a: \(a)\nb: \(b)")
print("a === b: \(a === b)")
print("a == b: \(a == b)")
var d = [a: "Hi"]
print("\(d[a]) \(d[b])")
let nA = NSUUID()
let nB = NSUUID(UUIDString: nA.UUIDString)!
print("na: \(nA)\nnB: \(nB)")
print("nA === nB: \(nA === nB)")
print("nA == nB: \(nA == nB)")
var nD = [nA: "Hi"]
print("\(nD[nA]) \(nD[nB])")
Results. Note that I can look up using NSUUID nB and get back what I put under nA. Not so with my BUUID.
a: 9DE6FE91-D4B5-4A6B-B912-5AAF34DB41C8
b: 9DE6FE91-D4B5-4A6B-B912-5AAF34DB41C8
a === b: false
a == b: true
Optional("Hi") nil
nA: <__NSConcreteUUID 0x7fa193c39500> BB9F9851-93CF-4263-B98A-5015810E4286
nB: <__NSConcreteUUID 0x7fa193c37dd0> BB9F9851-93CF-4263-B98A-5015810E4286
nA === nB: false
nA == nB: true
Optional("Hi") Optional("Hi")
Inheriting from NSObject also assumes isEqual(object: AnyObject?) -> Bool method overloading:
import Foundation
class BUUID: NSObject {
init?(str: String) {
if let uuid = NSUUID(UUIDString: str) {
_realUUID = uuid
}
else {
return nil
}
}
override init() {
_realUUID = NSUUID()
}
private var _realUUID: NSUUID
override func isEqual(object: AnyObject?) -> Bool {
guard let buuid = object as? BUUID else {
return false
}
return buuid._realUUID == _realUUID
}
override var description: String { get { return _realUUID.UUIDString } }
override var hashValue: Int { get { return _realUUID.hashValue } }
var UUIDString: String { get { print("WARNING Use description or .str instead"); return _realUUID.UUIDString } }
var str: String { get { return _realUUID.UUIDString } }
}
func ==(lhs: BUUID, rhs: BUUID) -> Bool { return lhs._realUUID == rhs._realUUID }
let a = BUUID()
let b = BUUID(str: a.str)!
print("a: \(a)\nb: \(b)")
print("a === b: \(a === b)")
print("a == b: \(a == b)")
var d = [a: "Hi"]
print("\(d[a]) \(d[b])")
let nA = NSUUID()
let nB = NSUUID(UUIDString: nA.UUIDString)!
print("na: \(nA)\nnB: \(nB)")
print("nA === nB: \(nA === nB)")
print("nA == nB: \(nA == nB)")
var nD = [nA: "Hi"]
print("\(nD[nA]) \(nD[nB])")
So the answer is to not make BUUID inherit from NSObject, which undercuts the Swiftiness of overriding ==.
So:
extension BUUID: Hashable {}
class BUUID: CustomStringConvertible {
// take away all 'override' keywords, nothing to override
// otherwise same as above
}
Interesting!
This answer is relevant to initially asked question: Why that's possible to get two key-value pairs with identical key's hashes in a dictionary
This example illustrates that keys in Dictionary can have identical hashes, but equality operation should return false for different keys:
func ==(lhs: FooKey, rhs: FooKey) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
class FooKey: Hashable, Equatable {
var hashValue: Int {
get {
return 123
}
}
}
var d = Dictionary<FooKey, String>()
let key1 = FooKey()
let key2 = FooKey()
d[key1] = "value1"
d[key2] = "value2"
Output
[FooKey: "value1", FooKey: "value2"]
That's definitely not good to have all keys with the same hash. In this case we are getting that worst case when search element complexity fells down to O(n) (exhaustive search). But it will work.

get the type/class of a property from its name in swift

Lets say I have this class:
class Node {
var value: String
var children: [Node]?
}
If I have the name of one of its properties (for example "children") how can I get its type? (In this case [Node]?)
I imagine having a global function like below will solve my needs:
func typeOfPropertyWithName(name: String, ofClass: AnyClass) -> AnyClass? {
//???
}
// Example usage:
var arrayOfNodesClass = typeOfPropertyWithName("children", Node.self)
Swift 2 (Note: Reflection changed):
import Foundation
enum PropertyTypes:String
{
case OptionalInt = "Optional<Int>"
case Int = "Int"
case OptionalString = "Optional<String>"
case String = "String"
//...
}
extension NSObject{
//returns the property type
func getTypeOfProperty(name:String)->String?
{
let type: Mirror = Mirror(reflecting:self)
for child in type.children {
if child.label! == name
{
return String(child.value.dynamicType)
}
}
return nil
}
//Property Type Comparison
func propertyIsOfType(propertyName:String, type:PropertyTypes)->Bool
{
if getTypeOfProperty(propertyName) == type.rawValue
{
return true
}
return false
}
}
custom class:
class Person : NSObject {
var id:Int?
var name : String?
var email : String?
var password : String?
var child:Person?
}
get the type of the "child" property:
let person = Person()
let type = person.getTypeOfProperty("child")
print(type!) //-> Optional<Person>
property type checking:
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalInt) ) //--> false
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalString) //--> true
or
if person.propertyIsOfType("email", type: PropertyTypes.OptionalString)
{
//true -> do something
}
else
{
//false -> do something
}
Reflection is achieved in Swift using the global reflect() function. When passing an instance of some type to reflect() it returns a MirrorType, which has a range of properties allowing you to analyze your instance:
var value: Any { get }
var valueType: Any.Type { get }
var objectIdentifier: ObjectIdentifier? { get }
var count: Int { get }
var summary: String { get }
var quickLookObject: QuickLookObject? { get }
var disposition: MirrorDisposition { get }
subscript(i: Int) -> (String, MirrorType) { get }
This seems to work:
func getTypeOfVariableWithName(name: String, inInstance instance: Any) -> String? {
let mirror = reflect(instance)
var variableCollection = [String: MirrorType]()
for item in 0..<mirror.count {
variableCollection[mirror[item].0] = mirror[item].1
}
if let type = variableCollection[name] {
let longName = _stdlib_getDemangledTypeName(type.value)
let shortName = split(longName, { $0 == "."}).last
return shortName ?? longName
}
return nil
}
Here's some example code on SwiftStub.
Edit:
The result for optional values is only "Optional".
The result for arrays is only "Array".
The result for dictionaries is only "Dictionary".
I'm not sure if it is possible to extract what kind of optional/array/dictionary it is. But I guess this would also be the case for custom data structures using generics.
Building on #PeterKreinz answer I needed to be able to check types of inherited properties as well so added a little to his above code:
extension NSObject {
// Returns the property type
func getTypeOfProperty (name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
while let parent = type.superclassMirror() {
for child in parent.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
type = parent
}
return nil
}
}
Hope this may help someone.
Swift 3 update:
// Extends NSObject to add a function which returns property type
extension NSObject {
// Returns the property type
func getTypeOfProperty (_ name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
while let parent = type.superclassMirror {
for child in parent.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
type = parent
}
return nil
}
}
The solution provided by #peter-kreinz using Swift's class Mirror works beautifully when you have an instance of a class, and want to know the types of the properties. However if you want to inspect the properties of a class without having an instance of it you might be interested in my solution.
I have a solution that finds the name and type of a property given any class that inherits from NSObject.
I wrote a lengthy explanation on StackOverflow here, and my project is available here on Github,
In short you can do something like this (but really check out the code Github):
public class func getTypesOfProperties(inClass clazz: NSObject.Type) -> Dictionary<String, Any>? {
var count = UInt32()
guard let properties = class_copyPropertyList(clazz, &count) else { return nil }
var types: Dictionary<String, Any> = [:]
for i in 0..<Int(count) {
guard let property: objc_property_t = properties[i], let name = getNameOf(property: property) else { continue }
let type = getTypeOf(property: property)
types[name] = type
}
free(properties)
return types
}