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.
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 need to use a protocol property in the conforming class as a private. But the compiler refuses that. How can I implement that?
protocol ProtocolX: class {
var x: Int { get set }
func performAnyActionOnX()
}
extension ProtocolX {
func performAnyActionOnX() {
x = 5
print(x)
}
}
class A: ProtocolX {
private var x:Int = 7
}
Thanks.
As #TheAppMentor mentioned, there seems to be no exact solution to this problem as of Swift 4.
There are, however, two approximate solutions:
1.)
Since a protocol in Swift has the access level of internal by default, make the variable also internal. In order for internal to be enforced by the compiler, move the protocol, the class and all of their consumers (users) to a separate module (framework).
/* internal */ protocol ProtocolX: class {
var x: Any { get set }
func performAnyActionOnX()
}
extension ProtocolX {
func performAnyActionOnX() {}
}
/* internal */ class A: ProtocolX {
internal var x: Any = 0
}
2.)
Give the protocol the access level of private and the variable the access level of fileprivate. In order for the private protocol to be accessible, move the protocol, the class and all of their consumers to the same source file.
private protocol ProtocolX: class {
var x: Any { get set }
func performAnyActionOnX()
}
extension ProtocolX {
func performAnyActionOnX() {}
}
class A: ProtocolX {
fileprivate var x: Any = 0
}
Since protocol's properties always have the same access level as your protocol has you can create a separate class where you can apply fileprivate level to them e.g.:
public class Props {
fileprivate var x: Int = 0
}
public protocol ProtocolX: class {
var privateProps: Props { get }
}
extension ProtocolX {
public func performAnyActionOnX() {
privateProps.x = 5
print(privateProps.x)
}
}
public class A: ProtocolX {
public let privateProps = Props()
public init() {
privateProps.x = 7
}
}
As you can see x has fileprivate access level so it can be accessible in ProtocolX extention and A class implementation only so it behaves as private and you can't change privateProps variable of class A and access to x outside:
let a = A()
a.performAnyActionOnX()
// Prints: 5
let x = a.privateProps.x
// error: 'x' is inaccessible due to 'fileprivate' protection level
There is no the exact solution for your question, by the reason stated in the #TheAppMentor's comment. But there some workarounds which may be helpful if you purpose is to make your code understandable for humans (not to trick the compiler).
Compiles in Swift 4.0.
Solution 1: Python-like __privacy
Fast and simple. This solution relies on the user who would agree that properties and functions starting from _ are private and shouldn't be accessed.
protocol ProtocolX: class {
// Public x
var x: Int { get }
// It's private!
var _x: Int { get set }
func performAnyActionOnX()
}
extension ProtocolX {
var x: Int { return _x }
func performAnyActionOnX(){
_x = 5
print(x)
}
}
class A: ProtocolX {
var _x: Int = 7
}
Solution 2: Additional layer of abstration
Architecturally correct. You should split your protocol on the two parts: private and public.
protocol ProtocolX: class {
var x: Int { get }
func performAnyActionOnX()
}
protocol ProtocolXImplementation: class {
var _x: Int { get set }
}
extension ProtocolXImplementation {
var x: Int { return _x }
func performAnyActionOnX(){
_x = 5
print(x)
}
}
class A: ProtocolX, ProtocolXImplementation {
var _x: Int = 7
}
// ... somewhere later ...
// Hide the implementation when use `A`:
let item: ProtocolX = A()
I want to write the following in Swift:
class A
{
class let x = 0
func print_class_property()
{
print(type(of: self).x)
}
}
class B:A
{
overriding class let x = 1
}
class C:A
{
overriding class let x = 5
}
A().print_class_property() // 0
B().print_class_property() // 1
C().print_class_property() // 5
But of course, this doesn’t compile.
Instead, I can demote the class property to a variable instance property that’s overwritten in the subclass initializers, but this allocates storage for x in every instance of A, B, or C. In addition you lose the guarantee that x never changes across the lifetime of the object.
How do I store constants at the class level, that can be shared by all instances of a subclass?
Unfortunately Swift (as for now) cannot have class stored properties that can be overriden. But can have class computed properties, which are overridable.
You can write something like this:
class A
{
class var x: Int {
return 0
}
func print_class_property()
{
print(type(of: self).x)
}
}
class B:A
{
override class var x: Int {
return 1
}
}
class C:A
{
override class var x: Int {
return 5
}
}
A().print_class_property() //->0
B().print_class_property() //->1
C().print_class_property() //->5
ADDITION
If you do not desire such re-evaluation as noted in comments, you may need to have some another static property.
For example:
class A
{
class var x: SomeLargeObject {
struct My {
static let obj = SomeLargeObject("abc", 0)
}
return My.obj
}
func print_class_property()
{
print(type(of: self).x)
}
}
class B:A
{
override class var x: SomeLargeObject {
struct My {
static let obj = SomeLargeObject("def", 1)
}
return My.obj
}
}
class C:A
{
override class var x: SomeLargeObject {
struct My {
static let obj = SomeLargeObject("ghi", 5)
}
return My.obj
}
}
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)
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