Cannot assign to property in protocol - Swift compiler error - ios

I'm banging my head against the wall with the following code in Swift. I've defined a simple protocol:
protocol Nameable {
var name : String { get set }
}
and implemented that with:
class NameableImpl : Nameable {
var name : String = ""
}
and then I have the following method in another file (don't ask me why):
func nameNameable( nameable: Nameable, name: String ) {
nameable.name = name
}
The problem is that the compiler gives the following error for the property assignment in this method:
cannot assign to 'name' in 'nameable'
I can't see what I'm doing wrong... The following code compiles fine:
var nameable : Nameable = NameableImpl()
nameable.name = "John"
I'm sure it's something simple I've overlooked - what am I doing wrong?

#matt's anwer is correct.
Another solution is to declare Nameable as a class only protocol.
protocol Nameable: class {
// ^^^^^^^
var name : String { get set }
}
I think, this solution is more suitable for this case. Because nameNameable is useless unless nameable is a instance of class.

It's because, Nameable being a protocol, Swift doesn't know what kind (flavor) of object your function's incoming Nameable is. It might be a class instance, sure - but it might be a struct instance. And you can't assign to a property of a constant struct, as the following example demonstrates:
struct NameableStruct : Nameable {
var name : String = ""
}
let ns = NameableStruct(name:"one")
ns.name = "two" // can't assign
Well, by default, an incoming function parameter is a constant - it is exactly as if you had said let in your function declaration before you said nameable.
The solution is to make this parameter not be a constant:
func nameNameable(var nameable: Nameable, name: String ) {
^^^
NOTE Later versions of Swift have abolished the var function parameter notation, so you'd accomplish the same thing by assigning the constant to a variable:
protocol Nameable {
var name : String { get set }
}
func nameNameable(nameable: Nameable, name: String) {
var nameable = nameable // can't compile without this line
nameable.name = name
}

Here, i written some code, that might give some idea on Associated generic type Usage:
protocol NumaricType
{
typealias elementType
func plus(lhs : elementType, _ rhs : elementType) -> elementType
func minus(lhs : elementType, _ rhs : elementType) -> elementType
}
struct Arthamatic :NumaricType {
func addMethod(element1 :Int, element2 :Int) -> Int {
return plus(element1, element2)
}
func minusMethod(ele1 :Int, ele2 :Int) -> Int {
return minus(ele1, ele2)
}
typealias elementType = Int
func plus(lhs: elementType, _ rhs: elementType) -> elementType {
return lhs + rhs
}
func minus(lhs: elementType, _ rhs: elementType) -> elementType {
return lhs - rhs
}
}
**Output:**
let obj = Arthamatic().addMethod(34, element2: 45) // 79

Related

Properties with generic type

Is it possible to have properties with generic type?
What I am trying to do:
Have a base class called Value with the following structure:
class Value {
var genericProperty: T
init<T>(type: T) {
switch type.self {
case is Int.Type:
genericProperty is Int
case is [Int.Type]:
genericProperty is [Int]
default:
genericProperty is Any
}
}
}
Then have a bunch of subclasses that define what the type of genericProperty should be.
Something like this:
class IntValue: Value {
override init<T>(type: T) {
super.init(type: Int.self)
}
}
class IntArrayValue: Value {
override init<T>(type: T) {
super.init(type: [Int.self])
}
}
Is this somehow possible with associatedType or any of the sorts?
For clarification (possibly this design is bad). I would like to do something along this line:
func handle(values: [Value]) {
values.forEach {
switch $0 {
case is IntValue.Type:
// Here I will now know that `genericProperty` will have type `Int`
// and can assign to a property with `Int` type
property: Int = $0.genericProperty
case is IntArrayValue.Type:
// Here I know it will be an array
...
}
}
}
Not sure if that's what you are looking for, but... you can create a generic base class and add subclasses which specify the concrete type:
class Value<T> {
var value: T
init(_ value: T) {
self.value = value
}
}
Now some subclasses with specific value type:
class IntValue: Value<Int> {}
class StringValue: Value<String> {}
And here's how to use them:
let intValue = IntValue(42)
intValue.value // 42
let stringValue = StringValue("Hi")
stringValue.value // "Hi"
In general the answer is no.
In your example, genericProperty would have a different type in the subclass to the superclass and that would break the type system. If you could do it, you could then legitmiately try something like this:
var array: [Value] = []
array.append(IntValue())
array.append(FloatValue())
for v in array
{
let foo = v.genericProperty
}
What should the compiler infer for the type of foo?

Swift 3 - Sequence ambiguous without more context

I tried to create a custom iterator which returns wrapper abcContainer over raw data class abc
// raw data class
class abc {
var name : String = "";
init( _ value : String) {
name = value;
}
}
// with container, only "name" is to be visible
class abcContainer {
private var _abc : abc;
init( _ obj : abc) {
_abc = obj;
}
// + extra methods here
func getName() -> String {
return _abc.name
}
}
The point would be that the dictionary would return instances of abcContainer instead of just the plain raw abc class.
I wanted to use the sequence protocol to make the conversion automatic, but I was not able to transform the [String:abc] into [String:abcContainer] automatically like this:
// the iterator is implemented just iterating the inner basic dict
// but wrapping the result value as abcContainer
class abcIterator : Sequence, IteratorProtocol {
private var __source : [String:abc]?;
var index = 0
var myIterator : DictionaryIterator<String, abc>;
init(_ ctxArray: [String:abc]) {
self.__source = ctxArray
index = 0;
myIterator = (__source?.makeIterator())!
}
func next() -> abcContainer? {
let nextItem = myIterator.next();
if(nextItem != nil) {
return abcContainer((nextItem?.value)!);
}
return nil;
}
}
// this was supposed to be the wrapper over the collection
class abcCollection : Sequence {
private var __source : [String:abc]?;
init(_ list: [String:abc]) {
self.__source = list
}
func makeIterator() -> abcIterator {
return abcIterator(self.__source!);
}
}
I'm probably missing something very basic here. When I try to use the collection like this:
var dict : [String:abc] = [String:abc]();
dict["abba"] = abc("John Smith");
for (key,value) in abcCollection(dict) {
print(key, value.getName());
}
I get error: Expression type "abcCollection" is ambiguous without more context
Does anyone have idea how to make it work? What is missing? I have a feeling that this answer has the information I need...
Swift 2 to 3 Migration for Swift Sequence Protocol
The problem in your original code is that abcCollection(dict)
returned a sequence of abcContainer objects, and those cannot
be assigned to a (key, value) tuple.
You can achieve your goal with
class abcCollection : Sequence {
private var __source : [String:abc]
init(_ list: [String:abc]) {
self.__source = list
}
public func makeIterator() -> AnyIterator<(AnyObject,abcContainer)> {
let mapped = self.__source.lazy.map {
($0.key as AnyObject, abcContainer($0.value))
}
return AnyIterator(mapped.makeIterator())
}
}
Making __source non-optional makes all the (optional) unwrappings
redundant, and lazy.map { ... } returns a lazily evaluated
sequence of key/value pairs which is then type-erased.
Ok, perhaps the answer was abcIterator was not necessary, you could have defined the iterator directly just like done in the linked answer like this:
class abcCollection : Sequence {
private var __source : [String:abc]?;
init(_ list: [String:abc]) {
self.__source = list
}
public func makeIterator() -> AnyIterator<(AnyObject,abcContainer)> {
var it = self.__source?.makeIterator();
return AnyIterator {
let n = it?.next();
if n == nil { return nil }
return (n?.key as AnyObject, abcContainer((n?.value)!))
}
}
}
After that, the custom collection returned wrapped objects correctly.

Swift Generic Unknown Member with Protocol Extension

If I have the following code:
protocol ObjectType {
var title: String { get set }
}
extension ObjectType {
var objectTypeString: String {
let mirror = Mirror(reflecting: self)
return "\(mirror.subjectType)"
}
}
class Object: ObjectType {
var title = ""
}
class SomeOtherClass {
private func someFunc<T: Object>(object: T) {
print(object.objectTypeString)
}
}
where Object conforms to ObjectType, you would expect that you can access objectTypeString on any ObjectInstance. But the compiler says that Type T has no member objectTypeString when that member is accessed on some generic type that inherits from Object, as shown in the code above. When the function is non-generic and just passes in an Object parameter, there's no issue. So why does have the parameter be generic make it so I can't access a member of the protocol that the conforming class should have access to?
I came across this question here but I'm not interested in workarounds, I'd just like to understand what it is about the generic system that makes my example not work. (Simple workaround is to do <T: ObjectType>)
Maybe I'm wrong or i didn't understand your question completely, but i think you might be missing initiating "object".
your willing code maybe the code below:
protocol ObjectType {
var title: String { get set }
}
extension ObjectType {
var objectTypeString: String {
let mirror = Mirror(reflecting: self)
return "\(mirror.subjectType)"
}
}
class Object: ObjectType {
var title = ""
}
class SomeOtherClass {
private func someFunc<T: Object>(object: T) {
let object = Object()
print(object.objectTypeString)
}
}
but the thing is, even if we dont initiate the object, the auto complete brings the objectTypeString up! that's what i don't understand, and as you said maybe its where the bug happens!
hope it helps <3

How to call static method provided by protocol in Swift

How to access to static protocol method within a instance
I have a list of Contact, the contact can be a FamilyContact that inherit from Contact and the GroupStatus protocol
I want to call the static method from GroupStatus but in vain...
Here is my code
protocol GroupStatus {
static func isPrivate() -> Bool // static method that indicates the status
}
protocol IsBusy {
func wizzIt()
}
class AdresseBook {
private var contacts = [Contact]()
func addOne(c: Contact) {
contacts.append(c)
}
func listNonPrivated() -> [Contact]? {
var nonPrivateContact = [Contact]()
for contact in contacts {
// here is I should call the static method provided by the protocol
if self is GroupStatus {
let isPrivate = contact.dynamicType.isPrivate()
if !isPrivate {
nonPrivateContact.append(contact)
}
}
nonPrivateContact.append(contact)
}
return nonPrivateContact
}
}
class Contact : Printable {
var name: String
init(name: String) {
self.name = name
}
func wizz() -> Bool {
if let obj = self as? IsBusy {
obj.wizzIt()
return true
}
return false
}
var description: String {
return self.name
}
}
class FamilyContact: Contact, GroupStatus {
static func isPrivate() -> Bool {
return true
}
}
I can't compile Contact.Type does not have a member named 'isPrivate'
How can I call it ? It works if I delete the static keyword, but I think is more logical to define it static.
If I replace
let isPrivate = contact.dynamicType.isPrivate()
by
let isPrivate = FamilyContact.isPrivate()
It works, but I can have more than 1 subclasses
If I remove the static keywork I can do it by this way :
if let c = contact as? GroupStatus {
if !c.isPrivate() {
nonPrivateContact.append(contact)
}
}
But I want to keep the static keyword
This looks like a bug or a non-supported feature. I would expect that
the following works:
if let gsType = contact.dynamicType as? GroupStatus.Type {
if gsType.isPrivate() {
// ...
}
}
However, it does not compile:
error: accessing members of protocol type value 'GroupStatus.Type' is unimplemented
It does compile with FamilyContact.Type instead of GroupStatus.Type. A similar problem is reported here:
Swift 1.1 and 1.2: accessing members of protocol type value XXX.Type' is unimplemented
Making isPrivate() an instance method instead of a class method is
the only workaround that I currently can think of, maybe someone comes
with a better solution ...
Update for Swift 2 / Xcode 7: As #Tankista noted below, this has
been fixed. The above code compiles and works as expected in Xcode 7 beta 3.
type(of: contact).isPrivate()
This should work in recent Swift.

Swift: how to return class type from function

I know it is possible to pass class type to a function in swift:
func setGeneric<T>(type: T.Type){ }
setGeneric(Int.self)
But how we can return type from function? Writing something like
func getGeneric<T>() -> T.Type {
return Int.self
}
gives compiler error "Int is not identical to T". So is it possible to return type from a swift function?
Edit
Some explanation. I have classes that are used for persistence (I'm using Realm) and I have classes that acts as wrappers around this classes. All wrappers inherits from RealmClassWrapper which needs to know what Realm class it actually wraps. So lets say I have this realm model:
class RealmTodo: RLMObject {
dynamic var title = ""
}
and my wrappers supper class looks like this:
class RealmClassWrapper {
private let backingModel: RLMObject
//...
func backingModelType<T>() -> T.Type{ fatalError("must be implemented") }
}
and actual wrapper:
class Todo: RealmClassWrapper {
//some other properties
func backingModelType<T>() -> T.Type{ return RealmTodo.self }
}
You can return any type you want.
func getTypeOfInt() -> Int.Type { return Int.self }
func getTypeOfBool() -> Bool.Type { return Bool.self }
If the type is not determined from arguments or if the return is constant, there is no need to introduce a generic T type.
It works when I modify your function like this:
func getGeneric<T>(object: T) -> T.Type {
return T.self
}
getGeneric(0) // Swift.Int
You can force the downcast (as!) as below
func getGeneric<T>() -> T.Type {
return Int.self as! T.Type
}
But out of the function scope, you need to indicate the returned type:
var t:Int.Type = getGeneric()
Yes, this is possible. The problem here is that you say your function returns a generic T.type, but you always return Int.type. Since T is not always an Int, the compiler raises an error.
If you don't want to specify the return type you can use AnyClass as it instead of a template parameter.
class A {}
class B {}
public enum ExampleEnum: String {
case a
case b
func asClass() -> AnyClass {
switch self {
case .a:
return A.self
case .b:
return B.self
}
}
}
let myGoal : AnyClass = ExampleEnum.a.asClass()
You can also avoid the final cast to AnyClass, but compiler will show you an error

Resources