I have a class that is generic, like:
class Row<T> {
...
}
If I have an instance of Row where T is ExampleClass, I want to be able to do:
row.bind(to: \ExampleClass.category)
Then in bind I want to start observing ExampleClass.category for my ExampleClass instance that I have in the class.
I've implemented:
func bind<Value>(to targetKeyPath: ReferenceWritableKeyPath<T, Value>) {
if let model = model as? NSObject {
model.observe(targetKeyPath, options: [.new ,.old], changeHandler: { _, change in
Log.info?.msg("Now we have some stuff: \(change)")
})
}
}
This gives me the error: Generic parameter 'Value' could not be inferred.
How is that possible? The T is solved but why can't Value be inferred? It should come from the parameter targetKeyPath.
Full code for repoducable:
class Row<T> {
let model: T
init(model: T) {
self.model = model
}
func bind<Value>(to targetKeyPath: ReferenceWritableKeyPath<T, Value>) {
if let model = model as? NSObject {
model.observe(targetKeyPath, options: [], changeHandler: { _, _ in
})
}
}
}
How I'd like to use the example class above:
class Person: NSObject {
#objc var age: NSNumber?
}
class Book: NSObject {
#objc var title: String?
}
let row1 = Row(model: Person())
let row2 = Row(model: Book())
row1.bind(to: \Person.age)
row2.bind(to: \Book.title)
You're probably over-thinking this. The problem is that model is known only to be an NSObject. You can reproduce simply like this:
class ExampleClass:NSObject {
#objc dynamic var category = ""
}
let model = NSObject()
model.observe(\ExampleClass.category) { _,_ in }
Same error. If you change model to be an ExampleClass, the problem goes away.
Related
I want access to SampleMoel's 'head' at ViewModel
How to fix this error?
this is MVVM(not Use combine, RxSwift ... only use Uikit)
SampleViewModel.swift
class SampleViewModel {
var model: SampleModel?
let changeData = Observer(model?.head) //Line error
init() {
self.model = SampleModel()
}
func changeLabel(_ tf: String) {
self.changeData.value = tf
}
}
SampleModel.swift
struct SampleModel {
var head = "initValue"
}
Modify your implementation as follows:
class SampleViewModel {
private let model: SampleModel
let changeData: Observer<String>
init(model: SampleModel) {
self.model = model
changeData = Observer(model.head)
}
func changeLabel(_ tf: String) {
self.changeData.value = tf
}
}
Imagine a situation that we have two classes like these:
class MyClass {
func printInstanceName() {
print(what?);
}
}
class User {
var firstObject: MyClass!
var secondObject: MyClass!
}
I will instantiate an object of class User like this:
let user = User();
user.firstObject = MyClass()
user.secondObject = MyClass()
How should i implement the printInstanceName that the output of code below
user.firstObject.printInstanceName()
user.secondObject.printInstanceName()
be
firstObject
secondObject
The purpose of doing this is, i want to know from which instance of MyClass in User, printInstanceName is called!
You can get variable name only in this way
class MyClass {
func printInstanceNameIn(user: User) {
let mirror = Mirror(reflecting: user)
for (label, value) in mirror.children {
if let value = value as? MyClass, value === self {
print(label!)
}
}
}
}
class User {
var firstObject: MyClass!
var secondObject: MyClass!
}
let u = User()
u.firstObject = MyClass()
u.secondObject = MyClass()
u.firstObject.printInstanceNameIn(user: u)
Use String(describing: type(of: self)) to print the class name.
class MyClass {
func printInstanceName() {
print(String(describing: type(of: self)))
}
}
Don't use force-unwrapped variables unnecessarily. You can create an init(myObject:) instead.
class User {
var myObject: MyClass
init(myObject: MyClass) {
self.myObject = myObject
}
}
Create User instance like,
let user = User(myObject: MyClass())
user.myObject.printInstanceName()
You cant get property name from MyClass, only from User.
class MyClass { }
class User {
var myObject: MyClass!
func printInstanceName() {
let mirror = Mirror(reflecting: self)
for (label, value) in mirror.children {
if type(of: value) == Optional<MyClass>.self {
print(label!)
}
}
}
}
let u = User()
u.printInstanceName()
I know this is not what you're exactly looking for but it might helps:
for child in Mirror(reflecting: user).children {
print(child.label)
}
I've followed the solution at Make a Swift dictionary where the key is "Type"? to create dictionaries that can use a class type as keys.
What I want to do is: I have one dictionary that should store class types with their class type (aka metatype) as keys, too:
class MyScenario {
static var metatype:Metatype<MyScenario> {
return Metatype(self)
}
}
var scenarioClasses:[Metatype<MyScenario>: MyScenario.Type] = [:]
Then I have methods to register and execute scenarios:
public func registerScenario(scenarioID:MyScenario.Type) {
if (scenarioClasses[scenarioID.metatype] == nil) {
scenarioClasses[scenarioID.metatype] = scenarioID
}
}
public func executeScenario(scenarioID:MyScenario.Type) {
if let scenarioClass = scenarioClasses[scenarioID.metatype] {
let scenario = scenarioClass()
}
}
... Problem is in the last line:
Constructing an object of class type 'MyScenario' with a metatype
value must use a 'required' initializer.
It looks like the compiler is confused at that point since I cannot use 'required' at that assignment. Does anyone have an idea how I would have to instantiate the scenarioClass in executeScenario()?
This must do the job.
import Foundation
struct Metatype<T> : Hashable
{
static func ==(lhs: Metatype, rhs: Metatype) -> Bool
{
return lhs.base == rhs.base
}
let base: T.Type
init(_ base: T.Type)
{
self.base = base
}
var hashValue: Int
{
return ObjectIdentifier(base).hashValue
}
}
public class MyScenario
{
var p: String
public required init()
{
self.p = "any"
}
static var metatype:Metatype<MyScenario>
{
return Metatype(self)
}
}
var scenarioClasses:[Metatype<MyScenario>: MyScenario.Type] = [:]
public func registerScenario(scenarioID:MyScenario.Type)
{
if (scenarioClasses[scenarioID.metatype] == nil)
{
scenarioClasses[scenarioID.metatype] = scenarioID
}
}
public func executeScenario(scenarioID:MyScenario.Type)
{
if let scenarioClass = scenarioClasses[scenarioID.metatype]
{
let scenario = scenarioClass.init()
print("\(scenario.p)")
}
}
// Register a new scenario
registerScenario(scenarioID: MyScenario.self)
// Execute
executeScenario(scenarioID: MyScenario.self)
// Should print "any"
I got stuck by the question in swift. Suppose I have one object, how to check whether it is from struct or class in swift.
In Swift 3.0, you can call Mirror(reflecting:x).displayStyle where x is your value of interest. The result will be class, struct, enum, dictionary, set... see the documentation https://developer.apple.com/reference/swift/mirror.displaystyle
Code sample:
struct SomeStruct {
var name: String
init(name: String) {
self.name = name
}
}
var astruct = SomeStruct(name:"myname")
Mirror(reflecting:astruct).displayStyle == .struct // will be true
Mirror(reflecting:astruct).displayStyle == .class; // will be false
class MyClass {
var name:String
init(name: String) {
self.name=name
}
}
var aclass = MyClass(name:"fsdfd")
Mirror(reflecting:aclass).displayStyle == .struct // will be false
Mirror(reflecting:aclass).displayStyle == .class // will be true
Of course, it would be best handled using a switch-case statement in practice.
This approach has been working for me in Swift 3:
class TestClass { }
struct TestStruct { }
var mystery:Any
mystery = TestClass()
// Is mystery instance a class type?
print(type(of:mystery) is AnyClass ? "YES" : "NO") // prints: "YES"
mystery = TestStruct()
// Is mystery instance a class type?
print(type(of:mystery) is AnyClass ? "YES" : "NO") // prints: "NO"
Note that this approach tells you only if an instance is a class type or not. The fact that it's not a class doesn't necessarily mean it's a struct (could be an enum, closure, tuple, etc.) But for most purposes and contexts this is enough to know if you are dealing with a reference type or a value type, which is usually what is needed.
There is is operator.
if someInstance is SomeType {
// do something
}
And there is as? operator.
if let someInstance = someInstance as? SomeType {
// now someInstance is SomeType
}
In swift4, checking class or struct
class TClass {}
struct TStruct {}
func who(_ any: Any) -> String {
if Mirror(reflecting: any).displayStyle == .class {
return "Class"
} else {
return "Struct"
}
}
print(who("Hello")) // Struct
print(who(TClass())) // Class
print(who(TStruct())) // Struct
print(who(1)) // Struct
You can do this by below given way and for more information on this please follow this link.
class Shape {
class func className() -> String {
return "Shape"
}
}
class Square: Shape {
override class func className() -> String {
return "Square"
}
}
class Circle: Shape {
override class func className() -> String {
return "Circle"
}
}
func getShape() -> Shape {
return Square() // hardcoded for example
}
let newShape: Shape = getShape()
newShape is Square // true
newShape is Circle // false
newShape.dynamicType.className() // "Square"
newShape.dynamicType.className() == Square.className()
A simple example for this:
var name = "Big Hero"
if name.isKindOfClass(NSString){
println("this is this class")
}else{
println("this is not this class")
}
I'm developing first app using Swift.
in one of my Class I need to store closure in an Array. Like an event manager :
typealias eventCallback = (eventName:String, data:[MasterModel]?) -> Void;
class MHttpLoader: NSObject
{
var eventRegister : [String: [eventCallback]];
class var instance : MHttpLoader
{
struct Static {
static let instance : MHttpLoader = MHttpLoader(baseURL:NSURL(string:"http://192.168.0.11:3000"));
}
return Static.instance;
}
class func registerEvent(eventName:String, callback:eventCallback)
{
if var tab = MHttpLoader.instance.eventRegister[eventName]
{
tab.append(callback);
}
else
{
MHttpLoader.instance.eventRegister[eventName] = [callback];
}
}
func fireEvent(eventName: String, data:[MasterModel]?)
{
if let tab = self.eventRegister[eventName]
{
for callback in tab
{
callback(eventName:eventName, data:data);
}
}
}
}
All this code work pretty well, the problem is when i want to remove a closure from my array.
For exemple :
class func removeEvent(eventName:String, callback:eventCallback)
{
if var tab :Array = MHttpLoader.instance.eventRegister[eventName]
{
if let index = find(tab, callback) as? Int
{
tab.removeAtIndex(index);
}
}
}
I have the error which says that my closure is not conform to protocol "Equatable"
I also tried :
class func removeEvent(eventName:String, callback:eventCallback)
{
if var tab :Array = MHttpLoader.instance.eventRegister[eventName]
{
tab = tab.filter({ (currentElement) -> Bool in
return currentElement != callback;
});
}
}
But I have the error : Cannot invoke '!=' with an argument list of type '((eventCallback), eventCallback)'
Here is my question how can i find the index of closure in array or simply compare closure?
Thank you