When I try to pass Swift nested class to function expecting AnyClass parameter I get following compiler error:
Expected member name or constructor call after type name
Is there a way I can fix above error and pass nested class as parameter?
func getInfo(type: AnyClass) -> UInt32
{
var outPropCount: UInt32 = 0
let properties: UnsafeMutablePointer<objc_property_t> = class_copyPropertyList(type, &outPropCount);
free(properties)
return outPropCount
}
public class Outer: NSObject
{
public class Data: NSObject
{
public var groups: [Int] = []
}
}
public class Data: NSObject
{
public var groups: [Int] = []
}
let o = getInfo(Outer) // works
let d = getInfo(Data) // works
let i = getInfo(Outer.Data) // fails to compile
Solution is to use .self to access type
let i = getInfo(Outer.Data.self)
Related
I am trying to create a wrapper for my API return wrapper class for my project.
these are my classes
class Wrapper<T> {
let message = "Hello World"
let wrapped = T.self
public func getData() -> T.Type {
return wrapped
}
}
class Object {
let number = 100
public func getNumber() -> Int {
return number
}
}
class SecondObject {
let name = "Second Object"
public func getName() -> String {
return name
}
}
What I want to achieve is, is there any way I can call the Object function like this
let example = Wrapper<Object>()
example.getData().getNumber() // <<-- This is not working
let secondExample = Wrapper<SecondObject>()
secondExample.getData().getName() // <<-- This is not working
The error in my playground is this
error: instance member 'getNumber' cannot be used on type 'Object'
If you notice the Wrapper class, there is message property which will be used for all my API return object model
So my goal is, I could simply call the Wrapper class together with my object model class and just call the function that is inside the object model class.
I am still learning about generic in swift. What am I missing here?
You don't set wrapped to anything useful. You ned to set it to an instance of T. So you can pass a Tinto the constructor
class Wrapper<T>
{
let wrapped: T
init(wrapped: T)
{
self.wrapped = wrapped
}
}
Or you can have the class construct an instance of T, but if you want to do that, you need to tell it how to construct the instance. For example:
class Wrapper<T>
{
let wrapped: T
init()
{
self.wrapped = T() // << error!
}
}
won't work because the compiler knows nothing about T, not even if it has an init. You can change that with a protocol
protocol Initable
{
init()
}
class Wrapper<T: Initable>
{
let wrapped: T
init()
{
self.wrapped = T()
}
}
And you can apply the protocol to any type you like with an extension. In most cases the extension can be empty because mot types already have an init() method. For example:
class MyClass
{
init() { /* do stuff */ }
}
extension MyClass: Initable {}
class MyOtherClass
{
init(number: Int) { /* do stuff */ }
}
extension MyOtherClass: Initable
{
init() { self.init(number: 0) }
}
Another option is to supply a closure to the wrapper's init.
class Wrapper<T>
{
let wrapped: T
init(factory: ()-> T)
{
self.wrapped = factory()
}
}
let w = Wrapper() { return Array<Int>() }
Normally you'd only do this if you wanted to create multiple instances i.e. you'd keep a reference to the closure and call it each time you needed a new instance.
class Wrapper<T> {
private var wrapped: T // Storing your object of T type
init(value: T) { // init with instance of T
wrapped = value
}
public func getData() -> T { //returning instance of T
return wrapped
}
}
class Object {
let number = 100
public func getNumber() -> Int {
return number
}
}
let o = Object()
let example = Wrapper(value: o) // Here we creating instance of Wrapper with instance of Object
example.getData().getNumber()
How about this , in your example changing the type of wrapped from non-optional to an optional variable type.
class Wrapper {
let message = "Hello World"
var wrapped : T?
public func getData() -> T? {
return wrapped
}
}
class Object {
let number = 100
public func getNumber() -> Int {
return number
}
}
class SecondObject {
let name = "Second Object"
public func getName() -> String {
return name
}
}
and then using it as below
let example = Wrapper()
example.wrapped = Object()
let result1 = example.getData()?.getNumber() // ()
secondExample.wrapped = SecondObject()
let result2 = secondExample.getData()?.getName()
if let val1 = result1 , let val2 = result2 {
print("result1 = \(val1) result2 = \(val2)" )
}
I want to "make" a number of class instances similar to a base class but different in underlying type. (Not quite the same as the typical "Animal" class factory examples seen all over the net!)
The code below is close to working but it requires the user to "upcast" the make result, as in:
var f1 = FOO.make(version: FOO.Ver.f1) as! FOO1_32
I do not want the user to know about the specific class type other than it is a FOO. I have seen other proposals and they all indicate that the solution is to define the make with a generic type that conforms to the protocol as in:
make<T: FOOProtocol>(version: Ver = .f1) -> T
However this gives me the error "generic parameter 'T' could not be inferred" on the call to FOO.make(version: FOO.Ver.f1)
Anyone know how to do this? My Playground code follows.
protocol FOOProtocol
{
associatedtype FOOtype
var value: FOOtype {get set}
}
class FOO
{
enum Ver
{
case f1
case f2
}
class func make(version: Ver = .f1) -> FOO
{
print("FOO make")
switch version
{
case .f1:
return FOO1_32()
case .f2:
return FOO2_64()
}
}
}
class FOO1_32: FOO, FOOProtocol
{
typealias FOOtype = UInt32
private var fooVal: UInt32 = 0
var value: UInt32
{
get { return self.fooVal }
set { self.fooVal = newValue }
}
override init()
{
print("FOO1_32 init")
self.fooVal = 132
}
}
class FOO2_64: FOO, FOOProtocol
{
typealias FOOtype = UInt64
private var fooVal: UInt64 = 0
var value: UInt64
{
get { return self.fooVal }
set { self.fooVal = newValue }
}
override init()
{
print("FOO2_64 init")
self.fooVal = 264
}
}
var f1 = FOO.make(version: FOO.Ver.f1) // requires: as! FOO1_32
let f1v = f1.value
print("\(f1v)")
var f2 = FOO.make(version: FOO.Ver.f2) // requires: as! FOO2_64
let f2v = f2.value
print("\(f2v)")
For example i have a BaseObject class:
class BaseObject: NSObject {
let id:UInt64
}
And manager class for this objects:
public class Manager: NSObject {
public var objs:[BaseObject] = []
public func addObj(obj:BaseObject) {
...
}
}
I want to create a library, and to allow developer set his own class that should inherit from Base Object
For example:
class MyOwnBaseObject: BaseObject {
var ownProperty:Int = 0
}
var manager = Manager();
manager.objClass = MyOwnBaseObject
and manager.objs should now return: [MyOwnBaseObject] and manager.addObj() should work with MyOwnBaseObject
Is this possible ?
If you want the return type to be of the subclass you specified, you can use generics:
public class BaseObject: NSObject {
let id:UInt64 = 0
}
public class MyOwnBaseObject: BaseObject {
var ownProperty:Int = 0
}
public class Manager<T>: NSObject {
public var objs:[T] = []
public func addObj(obj:T) {
objs.append(obj)
}
}
var manager = Manager<BaseObject>()
let ob1 = BaseObject()
manager.addObj(obj: ob1)
let ob2 = BaseObject()
manager.addObj(obj: ob2)
var otherManager = Manager<MyOwnBaseObject>()
let ownOb1 = MyOwnBaseObject()
otherManager.addObj(obj: ownOb1)
let ownOb2 = MyOwnBaseObject()
otherManager.addObj(obj: ownOb2)
print(manager.objs) // objs is of type [BaseObject]
print(otherManager.objs) // objs is of type [MyOwnBaseObject]
Without generics, you code would still work, but you would need to cast any of the objects returned by objs to the custom class (such as MyOwnBaseObject) to access any subclass-specific properties.
I have multiple classes with the same static variable. I get the currentInstance of each class at runtime(AnyObject?). Then I am trying to access static variables by getting a class from instance using type(of: instance) method. But when trying to get the static variable it throws me an error - Value of type 'AnyObject.Type' has no member . Here is pseudo code.
public extension Reader {
open static var funcDictionary = [String: readerFuncs]() //ReaderFuncs is an enum of functions
}
public extension Library {
open static var funcDictionary = [String: libraryFuncs]()
}
public extension ReaderMenu {
open static var funcDictionary = [String: readerMenuFuncs]()
}
import Foundation
open class TestClass: NSObject {
open func executeFunction(currentInstance: AnyObject) { // I get current instance at runtime. And I have checked that I get the correct value
var count = type(of: currentInstance).functionDictionary.count // Error: Value of type 'AnyObject.Type' has no member funcDictionary
}
I would like to know how to access static variables when you only have the instance of the class available. I have used .classforCoder() too but it doesn't work. All the files have the same target membership too.
You should use generic types in your TestClass executeFunction method, but we need a common reference to all three of your classes Reader, Library and ReaderMenu. To do that, we will create a protocol that each class has to conform to.
protocol Funcable {
associatedtype FuncsEnum
static var funcDictionary: [String:FuncsEnum] { get set }
}
Now each class inherits from Funcable, they are all required to have a typealias that defines the type of enum in the funcDictionary.
class Reader: Funcable {
typealias FuncsEnum = Reader.Funcs
static var funcDictionary = [String:FuncsEnum]()
enum Funcs {
case A
case B
}
}
class Library: Funcable {
typealias FuncsEnum = Library.Funcs
static var funcDictionary = [String:FuncsEnum]()
enum Funcs {
case C
case D
}
}
class ReaderMenu: Funcable {
typealias FuncsEnum = ReaderMenu.Funcs
static var funcDictionary = [String:FuncsEnum]()
enum Funcs {
case E
case F
}
}
You can define your enums outside of the classes if you like, but I've moved them inside to make it more reusable. Anyway back at the TestClass, we can use Generic Type Token T which is a mirror of the class of the given currentInstance.
class TestClass: NSObject {
func executeFunction<T: Funcable>(currentInstance: T) {
print(T.funcDictionary.count)
}
}
To access the enums individually e.g. Reader.Funcs instead of readerFuncs
UPDATE
We can just instantiate the currentInstance on our own to make it work.
let testInstance = TestClass()
Reader.funcDictionary.updateValue(.A, forKey: "a")
testInstance.executeFunction(currentInstance: Reader()) // prints 1
Library.funcDictionary.updateValue(.C, forKey: "c")
Library.funcDictionary.updateValue(.D, forKey: "d")
testInstance.executeFunction(currentInstance: Library()) // prints 2
Is it possible to get the object type from an optional?
For example, if I have a class that has a property that is an optional string, can I somehow just get back the string type?
The exact use case I have is I have many custom classes all of which have a property that is storing another custom class as an optional value. I would like to write a generic function that will create an instance of the object class stored in the optional.
Here is an example of what I am looking for, although .dynamicType does not work since it is an optional:
class Class1 {
}
class Class2 {
var myOp: Class1?
}
var c = Class2()
c.myOp = c.myOp.dynamicType()
Since you wanted to use this with Generics I tried it for you. It works, but it may not be so useful.
First some setup:
This is a helper protocol to make sure our Generic type will have a known init method.
protocol ZeroParameterInit {
init()
}
This is an extension to get the type from an optional:
extension Optional {
var dynamicWrappedType : Wrapped.Type {
return Wrapped.self
}
}
Implemented in your code:
class Class1 : ZeroParameterInit {
required init() {}
}
class Class2 {
var myOp: Class1?
}
var c = Class2()
c.myOp = c.myOp.dynamicWrappedType.init()
Generic implementation:
class Class1 : ZeroParameterInit {
required init() {}
}
class Class2<T where T : ZeroParameterInit> {
var attribute: Optional<T>// used long syntax to remind you of : Optional<Wrapped>
init(attr:T) {
attribute = attr
attribute = nil
}
}
The function to create the instance:
func myFunc<T>(instance: Class2<T>) -> T {
return instance.attribute.dynamicWrappedType.init()
}
Some tests:
let alpha = Class1()
let beta = Class2(attr: alpha)
beta.attribute = myFunc(beta)
The issue:
You can't create an instance of Class2 without informing it about the type of it's generic attribute. So you need to pass it some object/type and that complicates things again.
Some extra methods that might improve how it all works:
init() {
}
let delta = Class2<Class1>()
delta.attribute = myFunc(delta)
init(type:T.Type) {
}
let epsilon = Class2(type: Class1.self)
epsilon.attribute = myFunc(epsilon)
You just need to check if the optional exist:
func myFunc(c: Class2) -> Class1? {
if let c1 = c.myOp{
return c1.dynamicType()
}
return nil
}
OR
func myFunc(c: Class2) -> Class1? {
if c.myOp != nil{
return c.myOp!.dynamicType()
}
return nil
}
Note the your return type need to be optional as well.
Tried this in simulator, seems like doing the right thing, if I understood you
class Class1 {
}
class Class2 {
var myOp: Class1?
}
func myFunc(c: Class2) -> AnyObject {
if let c1 = c.myOp{
return c1.self
}
return c
}
var object = Class2()
object.myOp = Class1()
myFunc(object) // Class1