Cannot use mutating member on immutable value of type - swift

I have following struct:
public protocol SuperModel {
// empty protocol
}
struct ModelOne: SuperModel {
struct SubModelOne {
var someVar: Double
var othervar: Double?
}
var sub: SubModelOne?
mutating func setSub(sub: SubModelOne) {
self.sub = sub
}
}
In my class, I want to use this struct like that:
final class SomeClass: SuperClass {
var data: SuperModel
init() {
self.data = ModelOne()
}
func someFunc() {
(self.data as! ModelOne).setSub(ModelOne.SubModelOne(someVar: 2, otherVar: 1))
}
}
I get following error: Cannot use mutating member on immutable value of type 'ModelOne'. Why is that so and how can I fix this?

When you apply type casting to value types (such structs), if succeed, you receive immutable copy of requested value:
(self.data as! ModelOne) // this is copy of data
The only way (as known to me) how you can mutate values that need to be casted - reassign value (as #Sahil Beri pointed you need declare variable):
func someFunc() {
if var data = data as? ModelOne {
data.setSub(ModelOne.SubModelOne(someVar: 2, otherVar: 1))
self.data = data // you can do this since ModelOne conforms to SuperModel
}
}

Use like this,
struct UserAttributes {
var name:String?
var organizationID:String?
var email:String?
mutating func parseUserAttributes(attribues:[AWSCognitoIdentityProviderAttributeType])->UserAttributes{
for type in attribues{
if type.name == "name"{
name = type.value
}else if(type.name == "family_name"){
organizationID = type.value
}else if(type.name == "custom:role_id"){
role = type.value
}else if(type.name == "email"){
email = type.value
}
}
}
}
In some other file call like this,
var userAttributes = UserAttributes()
userAttributes = userAttributes.parseUserAttributes(attribues:attributes)

Problem is that you have declared data as SuperModel but allocate it as ModelOne. Declare data as ModelOne. Then the problem goes away.
final class SomeClass: SuperClass {
var data: ModelOne
init() {
self.data = ModelOne()
}
func someFunc() {
(self.data).setSub(ModelOne.SubModelOne(someVar: 2, otherVar: 1))
}
}

First downcast the self.data to ModelOne then call setSub function
if var data = self.data as? ModelOne {
data.setSub(ModelOne.SubModelOne(someVar: 2, othervar: 1))
}

#Shadow of is right. You try to mutate a temporary structure which is impossible and most of the time useless as it will be released once the mutation done. It's in fact a similar issue to trying to modify the return struct of a function. (see answer here : Cannot assign to property: function call returns immutable value)

In Swift 3, in my case, I was able to resolve the error just by changing struct to a class object.

Related

Swift extension with class: how to make a function to return an object's real type?

I have code like this:
class A{}
class B: A{
var val = 1
}
class C: A{
var num = 5
}
extension Optional where Wrapped == [B?]{
var vals: [B]{
var result = [B]()
if let arr = self{
for part in arr{
if let val = part{
result.append(val)
}
}
}
return result
}
}
extension Optional where Wrapped == [C?]{
var vals: [C]{
var result = [C]()
if let arr = self{
for part in arr{
if let val = part{
result.append(val)
}
}
}
return result
}
}
var one: [B?]? = [B()]
var two: [C?]? = [C(), nil]
print(one.vals.count)
print(two.vals.count)
Here is the optimized one:
Combined into one, for B ( A's subclass ) & C ( A's subclass )
extension Optional where Wrapped: Collection{
var vals: [A]{
var result = [A]()
if let arr = self{
for part in arr{
if let val = part as? A{
result.append(val)
}
}
}
return result
}
}
Now question comes,
for case like the follwing,
how to go on the optimization?
print(one.vals.first?.val ?? "")
print(two.vals.first?.num ?? "")
I guess, I need a function to return an object's real type
PS: I know , to handle data , struct is perfect with protocol
While it's a company project, & I'm a new one
You need to introduce an extra type variable to say that the extension works on Optionals where Wrapped.Element is another Optional of any type. You have to express the "any type" part with another type variable, but you cannot add this type variable in the extension's declaration (though this feature is being proposed), or the property's declaration. What you can do instead, is to make vals a function:
func vals<T>() -> [T] where Wrapped.Element == T? {
var result = [T]()
if let arr = self{
for part in arr{
if let val = part{
result.append(val)
}
}
}
return result
}
Note that this can be simplified to:
extension Optional where Wrapped: Sequence {
func vals<T>() -> [T] where Wrapped.Element == T? {
self?.compactMap { $0 } ?? []
}
}
Just for fun. Another possible approach to keep it as a computed property instead of a generic method is to create an AnyOptional protocol with an associatedtype Wrapped and conform Optional to it. Then you can create a computed property to return an array of its Wrapped Element Wrapped type:
protocol AnyOptional {
associatedtype Wrapped
var optional: Optional<Wrapped> { get }
}
extension Optional: AnyOptional {
var optional: Optional<Wrapped> { self }
}
extension AnyOptional where Wrapped: Sequence, Wrapped.Element: AnyOptional {
var elements: [Wrapped.Element.Wrapped] {
optional?.compactMap(\.optional) ?? []
}
}
print(one.elements) // "[B]\n"
print(two.elements) // "[C]\n"
print(one.elements.first?.val ?? "") // "1\n"
print(two.elements.first?.num ?? "") // "5\n"

Extension optional Array with Optional Element. Is it even possible?

I have a protocol FooProtocol. and a class Bar<Foo:FooProtocol>. Inside a class an Array var mess: [Foo?]? to keep [foo1, foo2, nil, foo3...] or nil
And I try to make extension for this array to count new Foo object. I prefer to have protocols, because Foos could be very different objects delivered from outer world.
protocol FooProtocol {
....
init(from heaven: Int)
}
extension Optional where
Wrapped: Collection,
Wrapped.Element == Optional,
Wrapped.Element.Wrapped: FooProtocol // 'Wrapped' is not a member type of 'Wrapped.Element'
{
var united: Wrapped.Element.Wrapped { // Nope
let i = ...
return Wrapped.Element.Wrapped(from: i) // Nope
}
}
class Bar<Foo:FooProtocol> {
var mess: [Foo?]?
init (with mess: [Foo?]?) {
self.mess = mess
}
var important: Foo {
return mess.united
}
}
Any ideas? I'm blocked.
Edit 1:
After Leo suggestions I changed some parts of my code. But still stucked. This time more code from Playgrounds.
Any object that could be converted into '[Double]'. Could be color (as RGBA), Bezier curve, square, whatever...
public protocol FooProtocol {
var atomized: () -> [Double] {get}
static var count: Int {get}
init(_ array:[Double])
init()
}
public extension Array where Element: FooProtocol {
var average: Element {
var resultAtoms: [Double] = []
let inputAtoms = self.map {$0.atomized()}
for i in 0..<Element.count {
let s = inputAtoms.reduce(into: 0.0, {$0 += $1[i]}) / Double (Element.count)
resultAtoms.append(s)
}
return Element(resultAtoms)
}
}
extension Optional where
Wrapped: Collection,
Wrapped.Element == Optional<FooProtocol>
{
typealias Foo = Wrapped.Element.Wrapped // Doesn't work. How to get class?
var average: Foo { // I cannot use Wrapped.Element, it's Optional
if let thatsList = self {
let withOptionals = Array(thatsList) // OK, its [Optional<FooProtocol>]
let withoutOptionals = thatsList.compactMap({$0}) // OK, its [FooProtocol]
// This is funny, called from class works and makes 'bingo'.
return withoutOptionals.average // Error: Value of protocol type 'FooProtocol' cannot conform to 'FooProtocol'; only struct/enum/class types can conform to protocols
} else {
return Foo() // Hello? init Wrapped? Foo? How to get Foo()?
}
}
}
class Bar<Foo:FooProtocol> {
var mess: [Foo?]?
init (with mess: [Foo?]?) {
self.mess = mess
}
func workOn() {
let z:Foo = mess.average // OK, I can make 'mess.average ?? Foo()' but prefer not do it
}
// Thats OK
func workHard() { // To prove 'Array extension where Element: FooProtocol' works
if let messExist = mess {
let withoutOptionals = messExist.compactMap({$0})
let bingo = withoutOptionals.average //It's OK
}
}
}
class SomeFoo : FooProtocol {
static var count = 3
required init() {
a = 0
b = 0
c = 0
}
required init(_ array: [Double]) {
self.a = Int(array[0])
self.b = Float(array[1])
self.c = array[2]
}
var atomized: () -> [Double] {
return {return [Double(self.a), Double(self.b), self.c]}
}
var a: Int
var b: Float
var c: Double
}
let aFoo = SomeFoo([1, 2, 3])
let bFoo = SomeFoo([7, 9, 1])
let cFoo = SomeFoo([2, 6, 5])
let barData = [nil, aFoo, nil, bFoo, cFoo]
let barWithData = Bar(with: barData)
let barWithoutData = Bar<SomeFoo>(with: nil)
Maybe I should forget about extending array and make some functions inside a class (I'm almost sure I will need those functions somewhere else)
Edit 2
Even if I try to simplify and to make extension for Array I found troubles.
extension Array where
Element == Optional<FooProtocol>
{
func averageNils <Foo: FooProtocol>() -> Foo {
let withOptionals = Array(self) // OK, its [Optional<FooProtocol>]
let withoutOptionals = self.compactMap({$0}) // OK, its [FooProtocol]
return withoutOptionals.average as! Foo // Error: Value of protocol type 'FooProtocol' cannot conform to 'FooProtocol'; only struct/enum/class types can conform to protocols
}
}
From my understanding, it should work as you did, but one never knows what happens in the swift compiler world (and especially it's error messages).
Anyway, you can circumvent digging deeper into Wrapped.Element.Wrapped by specifyig the Wrapped.Element more precisely to be an Optional<FooProtocol>:
protocol FooProtocol {}
class Foo : FooProtocol {}
extension Optional where
Wrapped: Collection, //OK
Wrapped.Element == Optional<FooProtocol> // still good
{
var unfied: Wrapped.Element // Should be 'Foo' if self is '[Foo?]?' {
{
return 1 == 0 ? nil : Foo()
}
}

Get all key paths from a struct in Swift 4

Let's say I have that struct:
struct MyStruct {
let x: Bool
let y: Bool
}
In Swift 4 we can now access it's properties with the myStruct[keyPath: \MyStruct.x] interface.
What I need is a way to access all it's key paths, something like:
extension MyStruct {
static func getAllKeyPaths() -> [WritableKeyPath<MyStruct, Bool>] {
return [
\MyStruct.x,
\MyStruct.y
]
}
}
But, obviously, without me having to manually declare every property in an array.
How can I achieve that?
DISCLAIMER:
Please note that the following code is for educational purpose only and it should not be used in a real application, and might contains a lot of bugs/strange behaviors if KeyPath are used this way.
Answer:
I don't know if your question is still relevant today, but the challenge was fun :)
This is actually possible using the mirroring API.
The KeyPath API currently doesn't allow us to initialize a new KeyPath from a string, but it does support dictionary "parsing".
The idea here is to build a dictionary that will describe the struct using the mirroring API, then iterate over the key to build the KeyPath array.
Swift 4.2 playground:
protocol KeyPathListable {
// require empty init as the implementation use the mirroring API, which require
// to be used on an instance. So we need to be able to create a new instance of the
// type.
init()
var _keyPathReadableFormat: [String: Any] { get }
static var allKeyPaths: [KeyPath<Foo, Any?>] { get }
}
extension KeyPathListable {
var _keyPathReadableFormat: [String: Any] {
let mirror = Mirror(reflecting: self)
var description: [String: Any] = [:]
for case let (label?, value) in mirror.children {
description[label] = value
}
return description
}
static var allKeyPaths: [KeyPath<Self, Any?>] {
var keyPaths: [KeyPath<Self, Any?>] = []
let instance = Self()
for (key, _) in instance._keyPathReadableFormat {
keyPaths.append(\Self._keyPathReadableFormat[key])
}
return keyPaths
}
}
struct Foo: KeyPathListable {
var x: Int
var y: Int
}
extension Foo {
// Custom init inside an extension to keep auto generated `init(x:, y:)`
init() {
x = 0
y = 0
}
}
let xKey = Foo.allKeyPaths[0]
let yKey = Foo.allKeyPaths[1]
var foo = Foo(x: 10, y: 20)
let x = foo[keyPath: xKey]!
let y = foo[keyPath: yKey]!
print(x)
print(y)
Note that the printed output is not always in the same order (probably because of the mirroring API, but not so sure about that).
After modifying rraphael's answer I asked about this on the Swift forums.
It is possible, discussion here:
Getting KeyPaths to members automatically using Mirror
Also, the Swift for TensorFlow team has this already built in to Swift for TensorFlow, which may make its way to pure swift:
Dynamic property iteration using key paths
I propose my solution. It has the advantage of dealing correctly with #Published values when using the Combine framework.
For the sake of clarity, it is a simplified version of what I have really. In the full version, I pass some options to the Mirror.allKeyPaths() function to change behaviour ( To enumerate structs and/or classes properties in sub-dictionaries for example ).
The first Mirror extension propose some functions to simplify properties enumeration.
The second extension implements the keyPaths dictionaries creation, replacing
#Published properties by correct name and value
The last part is the KeyPathIterable protocol, that add enumeration
capability to associated object
swift
// MARK: - Convenience extensions
extension String {
/// Returns string without first character
var byRemovingFirstCharacter: String {
guard count > 1 else { return "" }
return String(suffix(count-1))
}
}
// MARK: - Mirror convenience extension
extension Mirror {
/// Iterates through all children
static func forEachProperty(of object: Any, doClosure: (String, Any)->Void) {
for (property, value) in Mirror(reflecting: object).children where property != nil {
doClosure(property!, value)
}
}
/// Executes closure if property named 'property' is found
///
/// Returns true if property was found
#discardableResult static func withProperty(_ property: String, of object: Any, doClosure: (String, Any)->Void) -> Bool {
for (property, value) in Mirror(reflecting: object).children where property == property {
doClosure(property!, value)
return true
}
return false
}
/// Utility function to determine if a value is marked #Published
static func isValuePublished(_ value: Any) -> Bool {
let valueTypeAsString = String(describing: type(of: value))
let prefix = valueTypeAsString.prefix { $0 != "<" }
return prefix == "Published"
}
}
// MARK: - Mirror extension to return any object properties as [Property, Value] dictionary
extension Mirror {
/// Returns objects properties as a dictionary [property: value]
static func allKeyPaths(for object: Any) -> [String: Any] {
var out = [String: Any]()
Mirror.forEachProperty(of: object) { property, value in
// If value is of type Published<Some>, we transform to 'regular' property label and value
if Self.isValuePublished(value) {
Mirror.withProperty("value", of: value) { _, subValue in
out[property.byRemovingFirstCharacter] = subValue
}
} else {
out[property] = value
}
}
return out
}
}
// MARK: - KeyPathIterable protocol
protocol KeyPathIterable {
}
extension KeyPathIterable {
/// Returns all object properties
var allKeyPaths: [String: Any] {
return Mirror.allKeyPaths(for: self)
}
}

Get object type from optional?

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

Change the value that is being set in variable's willSet block

I'm trying to sort the array that is being set before setting it but the argument of willSet is immutable and sort mutates the value. How can I overcome this limit?
var files:[File]! = [File]() {
willSet(newFiles) {
newFiles.sort { (a:File, b:File) -> Bool in
return a.created_at > b.created_at
}
}
}
To put this question out of my own project context, I made this gist:
class Person {
var name:String!
var age:Int!
init(name:String, age:Int) {
self.name = name
self.age = age
}
}
let scott = Person(name: "Scott", age: 28)
let will = Person(name: "Will", age: 27)
let john = Person(name: "John", age: 32)
let noah = Person(name: "Noah", age: 15)
var sample = [scott,will,john,noah]
var people:[Person] = [Person]() {
willSet(newPeople) {
newPeople.sort({ (a:Person, b:Person) -> Bool in
return a.age > b.age
})
}
}
people = sample
people[0]
I get the error stating that newPeople is not mutable and sort is trying to mutate it.
It's not possible to mutate the value inside willSet. If you implement a willSet observer, it is passed the new property value as a constant parameter.
What about modifying it to use didSet?
var people:[Person] = [Person]()
{
didSet
{
people.sort({ (a:Person, b:Person) -> Bool in
return a.age > b.age
})
}
}
willSet is called just before the value is stored.
didSet is called immediately after the new value is stored.
You can read more about property observers here
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
You can also write a custom getter and setter like below. But didSet seems more convenient.
var _people = [Person]()
var people: [Person] {
get {
return _people
}
set(newPeople) {
_people = newPeople.sorted({ (a:Person, b:Person) -> Bool in
return a.age > b.age
})
}
}
It is not possible to change value types (including arrays) before they are set inside of willSet. You will need to instead use a computed property and backing storage like so:
var _people = [Person]()
var people: [Person] {
get {
return _people
}
set(newPeople) {
_people = newPeople.sorted { $0.age > $1.age }
}
}
Another solution for people who like abstracting away behavior like this (especially those who are used to features like C#'s custom attributes) is to use a Property Wrapper, available since Swift 5.1 (Xcode 11.0).
First, create a new property wrapper struct that can sort Comparable elements:
#propertyWrapper
public struct Sorting<V : MutableCollection & RandomAccessCollection>
where V.Element : Comparable
{
var value: V
public init(wrappedValue: V) {
value = wrappedValue
value.sort()
}
public var wrappedValue: V {
get { value }
set {
value = newValue
value.sort()
}
}
}
and then assuming you implement Comparable-conformance for Person:
extension Person : Comparable {
static func < (lhs: Person, rhs: Person) -> Bool {
lhs.age < lhs.age
}
static func == (lhs: Person, rhs: Person) -> Bool {
lhs.age == lhs.age
}
}
you can declare your property like this and it will be auto-sorted on init or set:
struct SomeStructOrClass
{
#Sorting var people: [Person]
}
// … (given `someStructOrClass` is an instance of `SomeStructOrClass`)
someStructOrClass.people = sample
let oldestPerson = someStructOrClass.people.last
Caveat: Property wrappers are not allowed (as of time of writing, Swift 5.7.1) in top-level code— they need to be applied to a property var in a struct, class, or enum.
To more literally follow your sample code, you could easily also create a ReverseSorting property wrapper:
#propertyWrapper
public struct ReverseSorting<V : MutableCollection & RandomAccessCollection & BidirectionalCollection>
where V.Element : Comparable
{
// Implementation is almost the same, except you'll want to also call `value.reverse()`:
// value = …
// value.sort()
// value.reverse()
}
and then the oldest person will be at the first element:
// …
#Sorting var people: [Person]
// …
someStructOrClass.people = sample
let oldestPerson = someStructOrClass.people[0]
And even more directly, if your use-case demands using a comparison closure via sort(by:…) instead of implementing Comparable conformance, you can do that to:
#propertyWrapper
public struct SortingBy<V : MutableCollection & RandomAccessCollection>
{
var value: V
private var _areInIncreasingOrder: (V.Element, V.Element) -> Bool
public init(wrappedValue: V, by areInIncreasingOrder: #escaping (V.Element, V.Element) -> Bool) {
_areInIncreasingOrder = areInIncreasingOrder
value = wrappedValue
value.sort(by: _areInIncreasingOrder)
}
public var wrappedValue: V {
get { value }
set {
value = newValue
value.sort(by: _areInIncreasingOrder)
}
}
}
// …
#SortingBy(by: { a, b in a.age > b.age }) var people: [Person] = []
// …
someStructOrClass.people = sample
let oldestPerson = someStructOrClass.people[0]
Caveat: The way SortingBy's init currently works, you'll need to specify an initial value ([]). You can remove this requirement with an additional init (see Swift docs), but that approach is much less complicated when your property wrapper works on a concrete type (e.g. if you wrote a non-generic PersonArraySortingBy property wrapper), as opposed to a generic-on-protocols property wrapper.