I have a class that needs to be set with a variable of a NSObject subclass and that implements a certain protocol.
protocol ProtoTest {
var foo: Int { get set }
}
class AClass: NSObject, ProtoTest {
var foo: Int = 3
}
class BClass: NSObject, ProtoTest {
var foo: Int = 4
}
class Consumer {
var protoInstance: ProtoTest? //Does not cary any information of the class just the protocol
var protoInstance2: protocol<NSObjectProtocol, ProtoTest>?
init(x: ProtoTest) {
self.protoInstance = x
self.protoInstance2 = nil
}
init(x: protocol<NSObjectProtocol, ProtoTest>) {
self.protoInstance2 = x
self.protoInstance = nil
}
func doSomething() {
if let x = protoInstance {
x.copy() //'ProtoTest' does not have a member named 'copy'
}
if let x = protoInstance2 {
x.copy() //protocol<NSObjectProtocol, ProtoTest> does not have a member named 'copy'
}
}
}
In the example above, neither declarations of the variable are gonna work. since neither of them have any knowledge of a base class?
How do I implement this in swift ?
The usual equivalent of NSObject<Protocol> in Swift is simply Protocol. Typically, this protocol is declared as a class protocol to guarantee that it will be adopted by a class.
If you also need the NSObject protocol methods (such a respondsToSelector:, then make Protocol adopt NSObjectProtocol.
If the problem is merely that you want to call copy() and you can't persuade the compiler to let you do it, then adopt NSCopying as well (or just use respondsToSelector: and performSelector: to bypass the compiler altogether).
You can do this a couple of ways. First, you can make Consumer generic:
class Consumer<T: NSObject where T: Prototest> {
var protoInstance: T?
var protoInstance2: T?
}
If you do that, then all references to protoInstance or protoInstance2 will inherit from NSObject, and you will be able to call methods like .copy() directly on the object.
If you don't want Consumer to be generic, you can enforce restraints on the init methods using generic parameters, like this:
class Consumer {
// ...
init<T: NSObject where T: Prototest>(x: T) {
protoInstance = x
}
}
If you do that, you will be guaranteed that protoInstance will be an NSObject, but you will have to cast to NSObject to use any of NSObject's methods:
func doSomething() {
if let x = protoInstance as? NSObject {
x.copy()
}
}
Edit:
Note that I wasn't sure if you really wanted protoInstance and protoInstance2 to be of different types I was a little unclear from your question. If you do want them to be different types, I can add additional suggestions to this answer.
Related
This code fails to compile with Swift 5.1
import Foundation
protocol SomeClassProtocol: AnyObject {}
class SomeClass: SomeClassProtocol {}
class GenericClass<T:AnyObject> {
weak var t: T?
init(t: T) {
self.t = t
}
}
let test = GenericClass<SomeClassProtocol>(t: SomeClass())
The error is
'GenericClass' requires that 'SomeClassProtocol' be a class type
Does the compiler really need a class type here instead of a class-only protocol?
Yes. Though the syntax is the same (a colon), protocol inheritance is not the same thing as protocol conformance. Protocols do not conform to protocols; only types can conform to protocols. (AnyObject is not special in this regard; your question is good but the title isn't getting at the issue.)
In your example:
Your T needs to conform to AnyObject. SomeClassProtocol does not conform to AnyObject. But any types that conform to SomeClassProtocol will conform to AnyObject.
So you need to pick which of these you really want:
1.
let test = GenericClass( t: SomeClass() )
(test is a GenericClass<SomeClass>.)
2.
class Class {
weak var object: AnyObject?
init(object: AnyObject) {
self.object = object
}
}
Class( object: SomeClass() )
You do have the option of subclassing, if that would be useful.
class GenericClass<T: AnyObject>: Class {
var t: T? {
get { object as? T }
set { object = newValue }
}
}
Does the compiler really need a class type here instead of a class-only protocol?
Yes, it does. I think the problem is just understanding what this means:
class GenericClass<T:AnyObject>
That means: "To resolve GenericClass, the parameterized type T must be some type that is a class." Examples would be UIView, NSString, etc.
Okay, so:
let test = GenericClass<SomeClassProtocol>(t: SomeClass())
So, SomeClassProtocol is none of those; it isn't the name of a class. It's the name of a protocol.
A further difficulty may be understanding protocols as types. They are not really full-fledged types.
You don't need to specify T explicitly.
Change your code from this:
let test = GenericClass<SomeClassProtocol>(t: SomeClass())
To this:
let test = GenericClass(t: SomeClass())
So far I have only worked on Objectiv-C projects and now started my first Swift project.
I know that Swift does not support abstract classes but I would like to know what is the best way to model / solve this in Swift:
// Abstract implementation
public abstract class MyClass {
private SomeBaseClass someProperty;
MyClass() {
initProperties();
}
abstract void initProperties(); // Init someProperty with some child class of SomeBaseClass.
}
// Objectiv-C
#implementation MyClass
- (id)init {
self = [super init];
if (self) {
[self initProperties];
}
return self;
}
- (void)initProperties {
// Override in inherited classes
}
// Swift
class MyClass {
// Should not be optional since MyClass should be required to have someProperty != nil
let someProperty: SomeBaseClass;
override init() {
super.init();
initProperties();
}
func initProperties() {
// Cannot be empty since someProperty is non-optional and needs to be initialized
// Cannot be empty since Swift does not support abstract methods
}
}
Of course it would be possible to define someProperty as optional SomeBaseClass? but in this case every time the property is used it has to be tested and unwrapped.
Is there a better way to solve this?
EDIT:
I know that Swift uses protocols to create an abstraction similar to abstract classes. However I do not understand how this concept can solve the concrete problem / question.
In other programming languages the abstract class MyClass can use the property someProperty in many different places while leaving the burden to initialize the property with a value with its concrete subclasses.
Although I read the article linked by #MohamendS and the answers to the possible dublicate answer I do not understand how to achieve the same using protocols.
MyClass has only one abstract function while all other functions are implemented. Thus MyClass itself cannot be a protocol since protocols cannot implement functions (can they?)
MyClass could only implement another protocol which defines that there has to be a initProperties method. But in this case MyClass would need to provide an implementation of this method which brings us back to the same problem.
I guess I can't see the wood for the trees, but how can protocols help here?
Abstraction concept in Swift is used with protocols, i suggest reading this article to know more and here is an example
protocol Abstraction {
var foo: String { get }
func fee()
init(with foo: String)
}
class A: Abstraction {
required init(with foo: String) {
self.foo = foo
}
var foo: String = ""
func fee() {
}
}
Edit: on your point, that
protocols can't implement functions
You can't but what you can do is extends those protocols using extension and give them an initial implementation therefore you don't have to implement them in the class and you can when you feel you'd like to, check the code below
class A: Abstraction {
required init(with foo: String) {
self.foo = foo
}
var foo: String = ""
//you don't have to implement func foo anymore as its extended in the extension
}
extension Abstraction {
func fee() {
print("ok")
}
}
let a = A(with: "foo")
a.fee() // this will trigger the extension implementation,
Now to use init inside the extension body so you wont have to type them in each confirmation, check out the code below
protocol Abstraction {
var foo: String { get set }
func fee()
init()
init(with foo: String)
}
class A: Abstraction {
required init() { }
var foo: String = ""
//you don't have to implement func foo anymore as its extended in the extension
// you don't have to implement the custom init anymore too
}
extension Abstraction {
init(with foo: String) {
self.init()
self.foo = foo
}
func fee() {
print("ok")
}
}
There are many possible answers to this question depending on how MyClass is used. As written, there's of course no reason for someProperty to be in the base class at all, and there's definitely no reason for an initProperties() method (that should be in init).
I realize this is "just an example," but it demonstrates a common problem of creating hierarchies that aren't needed. There are ways to write this code using a semi-abstract base class, but generally that should be avoided, so the first question is what you're using this for and can we avoid this problem entirely?
To answer the question as given, you'd probably start by making a default SomeBaseClass, so that the abstract class can just assign someProperty = SomeBaseClass().
If that's impossible, generally you'd use a ! type:
let someProperty: SomeBaseClass!
And you implement initProperties() with a fatalError:
func initProperties() { fatalError("Implement in subclass") }
Alternately, it can be convenient to implement someProperty as a computed variable, and implement it based on some other property in the subclasses
var someProperty: SomeBaseClass { fatalError() }
But this is really a last resort. Any time you find yourself having to write fatalError you're probably on the wrong track, and you don't need a trick to get around it; you need to reconsider the problem.
You should first think about how MyClass is used, and consider whether it can be a value type. Separately, you should think about whether it can be a protocol that matches the use case. Protocols are not just abstract interfaces that hide implementations. They are a view onto a conforming type to solve a specific problem. That's why there's a Collection protocol that provides access to dozens of algorithms for numerous, otherwise unrelated types, not an ArrayProtocol just to hide the implementation of Array. Don't turn MyClass into MyClassProtocol. Ask what kinds of algorithms want to use types like this one.
When you find yourself creating interlocking hierarchies of types (subclasses of something that require subclasses of some other thing), you have often sliced the problem in the wrong direction. You should rethink whether you could slice the problem so that the varying parts of SomeBaseClass are actually part of MyClass (often this makes SomeBaseClass simpler; for example being pure data rather than having logic).
There's no one right answer here. It depends on the nature of MyClass, so we can't really discuss it in abstract terms. Like abstract classes, solving abstract problems often leads you down the wrong roads. It's often better to start with concrete types and then find their similarities and extract them.
Even with that said, it's worth showing what a simple, naive protocol would look like here. (It's possible this is even the correct protocol.)
public protocol MyProtocol {
var someProperty: SomeBaseClass { get }
}
That's it. That's all you actually express in your current abstract class (and it's not actually clear whether someProperty is public; if it's private, this protocol would be empty).
An implementing struct would then look like:
struct MyStruct: MyProtocol {
var someProperty: SomeBaseClass
}
Or if you wanted a reference type, you could use a final class:
final class MyClass: MyProtocol {
var someProperty: SomeBaseClass
init() {
someProperty = ...
}
}
Or if you wanted inheritance, you could use a non-final class:
class MyClass: MyProtocol {
var someProperty: SomeBaseClass
init() {
someProperty = ...
}
}
I have some protocol hierarchies on my code where I have protocols defining the objects I use and protocols defining functions to use with this objects.
The object protocols are inherited by other object protocols that add more functionality to the original protocols and so are the functions that use them. The problem is that I can't find a way to specialize the function to take only the inherited parameter.
Here's some code to clarify what I'm trying to do:
protocol A {
var foo: String { get set }
}
protocol B: A {
var bar: String { get set }
}
struct Test: B {
var foo: String = "foo"
var bar: String = "bar"
}
protocol UseAProtocol {
static func use<T: A>(_ obj: T)
}
protocol UseBProtocol: UseAProtocol {
}
extension UseBProtocol {
//If I change the requirement to <T: B> this won't conform to `UseAProtocol`.
static func use<T: A>(_ obj: T) {
print(obj.foo)
// print(obj.bar) - Since obj does not conform to `B` I can't access ".bar" here without a forced casting.
}
}
struct Manager: UseBProtocol {
}
Manager.use(Test())
What I want to do is make the use function on the UseBProtocol only accept objects that conform to B. B inherits from A, but when I change from <T:A> to <T:B> I got an error saying that Manager does not conform to UseAProtocol and I have to change it back to <T:A>.
I know I can do this using associatedtype and where clauses on the inherit protocols - that's what I use today - but I wanted to move the generic requirement to the method so I could group all of them together under the same struct (I have a lot of this hierarchies and by using associatedtype I must use one struct by hierarchy). When the Conditional Conformances came to Swift this would be possible with associatedtype, but until them...
I could also use as! to force the casting from A to B on the UseBProtocol implementation, but that's a really bad solution and the error would be throw only at runtime.
Is there any way to achieve what I'm looking for?
It seems like what you are actually looking for is an associatedType in UseAProtocol rather than making the use function generic.
By declaring an associated type in UseAProtocol and changing the function signature of use to static func use(_ obj: ProtocolType) your code compiles fine and you can access both foo and bar from Manager.
protocol AProtocol {
var foo: String { get set }
}
protocol BProtocol: AProtocol {
var bar: String { get set }
}
struct Test: BProtocol {
var foo: String = "foo"
var bar: String = "bar"
}
protocol UseAProtocol {
associatedtype ProtocolType
static func use(_ obj: ProtocolType)
}
protocol UseBProtocol: UseAProtocol {
}
extension UseBProtocol {
static func use(_ obj: BProtocol) {
print(obj.foo)
print(obj.bar)
}
}
struct Manager: UseBProtocol {
}
Manager.use(Test()) //prints both "foo" and "bar"
Is it possible to implicitly pass self as an inout parameter to modify a reference variable in place?
Here is a method which can convert an abstract base class into one of its concrete subclasses. My question is, must I always have that first argument, obj: inout AbstractBaseClass, or can I implicitly pass self. I realize that this might also be expressed as a static method.
func convertTo(_ obj: inout AbstractBaseClass, _ type: ConcreteClassTypes) {
switch type {
case .concreteClass1: obj = ConreteClass1()
case .concreteClass2: obj = ConcreteClass2()
}
}
Here is the full code:
class AbstractClass {
enum ConcreteType {
case concreteClass1
case concreteClass2
}
var id: Int = 0
fileprivate init() { }
func convert(_ obj: inout AbstractClass, to type: ConcreteType) {
let oldId = obj.id
switch type {
case .concreteClass1: obj = ConcreteClass1()
case .concreteClass2: obj = ConcreteClass2()
}
obj.id = oldId
}
class ConcreteClass1: AbstractClass {
override init() { super.init() }
}
class ConcreteClass2: AbstractClass {
override init() { super.init() }
}
}
var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj.convert(&obj, to: .concreteClass2) //is there any way to eliminate this first argument?
Like matt, I'm not convinced that inout is the right tool for the job in this case.
Although that being said, if you insist on it, one way to achieve what you want is to (ab)use protocol extensions. They allow the definition of mutating methods, which pass the implicit self parameter as inout (to allow the mutation of adopting value types).
So you could say:
protocol AbstractClassProtocol {}
class AbstractClass : AbstractClassProtocol {
enum ConcreteType {
case concreteClass1
case concreteClass2
}
fileprivate init() {}
class ConcreteClass1: AbstractClass {
override init() { super.init() }
}
class ConcreteClass2: AbstractClass {
override init() { super.init() }
}
}
extension AbstractClassProtocol where Self == AbstractClass {
mutating func convert(to type: AbstractClass.ConcreteType) {
switch type {
case .concreteClass1:
self = AbstractClass.ConcreteClass1()
case .concreteClass2:
self = AbstractClass.ConcreteClass2()
}
}
}
var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj.convert(to: .concreteClass2)
print(obj) // AbstractClass.ConcreteClass2
But it's a bit of a hack, and I'd be wary about using it.
...to modify a reference variable in place? Here is a method which can convert an abstract base class into one of its concrete subclasses...
You are not "modifying" or "converting" anything. You are substituting one object for another. Thus, there is no self that could be passed here; the idea of what you are doing is to destroy one self and provide another in its place.
That said, it's a little unclear what the inout variable is for. Why don't you just assign the new object in place of the old object?
func giveMeA( _ type: AbstractClass.ConcreteType) -> AbstractClass {
switch type {
case .concreteClass1: return AbstractClass.ConcreteClass1()
case .concreteClass2: return AbstractClass.ConcreteClass2()
}
}
var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj = giveMeA(.concreteClass2)
The effect is identical to what you're doing. If you think it's not, you're just kidding yourself about what the inout parameter is doing.
I'm going to propose a completely different way of looking at what you're trying to do.
Don't have an abstract superclass. Don't have multiple subclasses. Have one class with multiple functional variants. The functional variants are expressed by a helper object — a struct — owned by the class instance.
So to change functionalities, you just set the helper to a different type of helper. Basically, you give your object a personality transplant.
I have an app that works that way. I have four view controllers that present slightly different info in slightly different ways. But in fact they are one view controller and an enum with four cases that dictates those differences. Thus, at any time the view controller can manifest itself as any of the four types.
I have the following protocol defined in Swift:
protocol RecordingObserver {
func aFunc()
}
Somewhere I have to compare two objects that implement this protocol, to check if they are the same. The problem I'm facing is that apparently Swift doesn't allow us to do this:
func areEqual(a:RecordingObserver,b:RecordingObserver){
if a === b {
println("Equal")
}
}
Any idea why this is happening? And how I can do this in another way?
=== is the identical to operator and is used to test whether two object references both refer to the same object instance. It can be applied
only to reference types (i.e. instances of a class).
=== is different from the "equal to" operator == (which is required in the Equatable protocol).
Therefore, assuming that
the actual observers are instances of a class, and
your intention is to check if a and b refer to the same instance,
you have to define the protocol as a class protocol:
protocol RecordingObserver : class {
// ...
}
Then
func areEqual(a:RecordingObserver,b:RecordingObserver){
if a === b {
println("a and b refer to the same object instance")
}
}
compiles (and works as expected) because the compiler knows that a and b are reference types.
Your class needs to support the Equatable protocol to use ==
https://developer.apple.com/library/ios/documentation/General/Reference/SwiftStandardLibraryReference/Equatable.html
Or if you want to use === something like this...
protocol RecordingObserver {
func aFunc()
}
class MyClass: RecordingObserver {
func aFunc() {
// Do something
}
}
func areEqual(a: MyClass, b: MyClass){
if a === b {
println("Equal")
}
}
I believe there is an 'isEqual' method on NSObject. If your custom objects are both subclassed from that you should be able to compare a.isEqual(b).
It is because you said that you objects implement only RecordingObserver. So compiler don't know if he can compare them.
Try this:
func areEqual<T where T: Equatable, T: RecordingObserver>(a: T,b: T) {
}
You can just copy this code into single view project to test:
protocol RecordingObserver {
}
class SomeClass: NSObject, RecordingObserver {
}
class ViewController: UIViewController {
func areEqual<T where T: Equatable, T: RecordingObserver>(a: T,b: T) -> Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
let a = SomeClass()
let b = SomeClass()
NSLog("\(areEqual(a, b: b))")
}
}