简体   繁体   中英

Same reference for all the objects in iOS swift

In swift 4.2 I am facing the problem while handling the two array objects, When I am removing objects from another array, the values are removed from the all the objects.

1) Below is my closure

func GetChatBotData(completion: @escaping (_ result: ChatV_1_Model) -> Void) {

    var ChatBotData : ChatV_1_Model! = nil
    ApiHelper.sharedSession.postLoacl("http://localhost:3000/posts/", postData: NSDictionary(), methodtype: Constant.API.httpGet) { (isError, data, errorDescription) in

        DispatchQueue.main.async(execute: {
            if isError == false {
                ChatBotData = ChatV_1_Model.init(fromDictionary: data!)
                completion(ChatBotData)
            }
            else {
                //completion("Error to get result" as AnyObject)
                completion(ChatBotData)
            }
        })
    }
}

Now In my controller

var PKComponents = [Chatbot_V_1_DataModel]()
var ChatMessages = [Chatbot_V_1_DataModel]()

override func viewDidLoad() {
    super.viewDidLoad()

     GetChatBotData() {(result: ChatbotV_1_Model!) in
        print("Call Plans: \(result!)")

        self.PKComponents = result.data
        self.ChatMessages = result.data
        self.ChatMessages[0].component.removeAll()
    }

In Viewdidload I am removing objects from self.ChatMessages array but it removes from all the objects like, PKComponents and result.data as well.

Note: I have seen the reference of the result is same as PKComponents and Chatmessages.

How to resolve this?

Here's the simplified example, where I can reproduce your problem:

class Component {

}
class SomeData {
    var components: [Component]
    init(components : [Component]) {
        self.components = components
    }
}

class Result {
    var data: [SomeData]
    init(data: [SomeData]) {
        self.data = data
    }
}




let someData = SomeData(components: [Component()])
let result = Result(data: [someData])

//problem begins here
let pkCompent = result.data
var chatMsgs = result.data
print(pkCompent[0].components.count)
chatMsgs[0].components.removeAll()
print(pkCompent[0].components.count)

Inorder to avoid the reference issue, convert SomeData to struct

struct SomeData {
    var components: [Component]
    init(components : [Component]) {
        self.components = components
    }
}

This is the problem of deep copying. Either you write a complete initializer that copies everything and create a new object and use that instead of just assignment. Or use struct instead of class. But as a quick fix you can explicitly only copy the component array like this:

self.PKCOMPONENTS = results.data
self.PKCOMPONENTS.components = Array(results.data.components)

You have 2 suggestions.

1- Deep copy .
2- Use struct instead of class since its value type.

Incase of deep copy this is a simple example, when you assign something to new instance use this way.

// Deep copy
var foo = Foo()
var otherFoo  = Foo(foo)

rather than this.

var fee = foo // shallow copy still the same referance 

Note: this is handled by swift you don't have to add any inits to the class.

  • component is what you are removing it from and not the Array to be precise.

  • While arrays implementation in swift is using a Struct which is a value type and not a Object type, what your array is holding, ie Object of Chatbot_V_1_DataModel might as well be a class thus, the elements held in your array are references to object of type Chatbot_V_1_DataModel.

  • the way you can work around this is by having Chatbot_V_1_DataModel defined as a struct thus, a value type OR by making a deep copy of you array and then using that copy in you closure as you modify it.

I am talking about something on these lines:

var copie = arr.map{$0.mutableCopy()}

better yet:

var PKComponents = [Chatbot_V_1_DataModel]()
var ChatMessages = [Chatbot_V_1_DataModel]()

override func viewDidLoad() {
super.viewDidLoad()
 var copie = arr.map{$0.mutableCopy()} // use this copy now elsewhere!!!
 GetChatBotData() {(result: ChatbotV_1_Model!) in
    print("Call Plans: \(result!)")

    self.PKComponents = result.data
    self.ChatMessages = result.data
    self.ChatMessages[0].component.removeAll()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM