2015-12-27 20 views
6

Tôi muốn chuyển một mảng tới một đối tượng và lưu trữ một tham chiếu đến mảng này. Tôi muốn có thể sửa đổi mảng này trong đối tượng này và đảm bảo rằng nó được sửa đổi ở mọi nơi khác.Lưu trữ một tham chiếu đến mảng trong swift

Đây là những gì tôi đang cố gắng để thực hiện (cách mã không hoạt động)

class Foo { 
    var foo : Array<Int> 

    init(foo: Array<Int>) { 
     self.foo = foo 
    } 

    func modify() { 
     foo.append(5) 
    } 
} 

var a = [1,2,3,4] 
let bar = Foo(a) 
bar.modify() 
print(a) // My goal is that it will print 1,2,3,4,5 

phát hiện của tôi cho đến nay

A) Mảng (theo mặc định) được thông qua cách kỳ lạ. Đó là một tham chiếu cho đến khi bạn sửa đổi độ dài mảng. Ngay sau khi bạn sửa đổi độ dài, nó sẽ được sao chép và sửa đổi. Do đó, nếu tôi nối hoặc xóa bất kỳ thứ gì từ nó trong đối tượng, nó sẽ không được nhìn thấy bên ngoài

B) Tôi có thể sử dụng inout trên tham số chức năng. Điều này sẽ cho phép tôi sửa đổi nó trong hàm này. Tuy nhiên, ngay sau khi tôi sẽ cố gắng gán nó cho một số thành viên đối tượng, tôi lại bị ấn tượng bởi A)

C) Tôi có thể bọc một mảng trong một số lớp Container. Đây có lẽ là cách sạch nhất. Tuy nhiên, tôi tuần tự hóa/deserialize các đối tượng này và tôi không muốn đặt nó trong Container (vì tôi sẽ phải làm việc xung quanh một số thứ cho serialization và deserialization và gửi nó đến máy chủ).

Còn gì khác không? Tôi có thiếu một số cấu trúc Swift cho phép tôi làm điều đó không?

+0

Bạn muốn thay đổi "a" tuyên bố đó là hằng số như thế nào? Ngoài ra, bạn sẽ cần phải vượt qua nó bằng cách sử dụng tham số inout và vượt qua nó vào phương pháp của bạn với "&" tiền tố –

+0

Tôi có thể thay đổi "a" là một var. Sử dụng & và tham số inout sẽ chỉ hoạt động nếu tôi sửa đổi mảng chỉ trong phương thức mà nó được truyền. Ngay khi tôi làm "self.foo = foo" nó sẽ ngừng hoạt động. Có nghĩa là sửa đổi self.foo sẽ không ảnh hưởng đến "a" –

+0

khai báo nó là var, xác định var foo: [Int] = [] {willSet (newArray) {a = newArray}} –

Trả lời

0

Từ the Swift Programming Language,

Structures are always copied when they are passed around in your code, and do not use reference counting.

Nếu bạn kiểm tra các nội dung của biến mảng, bạn sẽ thấy rằng thực sự là append hoạt động:

 
class Foo { 
    var foo : Array 

    init(_ foo: Array) { 
    self.foo = foo 
    } 

    func modify() { 
    foo.append(5) 
    } 

    func printFoo() { 
    print("self.foo: \(foo)") 
    } 
} 

let a = [1,2,3,4] 
let bar = Foo(a) 
bar.modify() 
bar.printFoo() 
print("a: \(a)") 

sản xuất

 
self.foo: [1, 2, 3, 4, 5] 
a: [1, 2, 3, 4] 

Bạn đã chụp c opy của số, không phải là số tham chiếu đến.

+0

Có. Tôi biết rằng nó sẽ gắn thêm vào một mảng bên trong của đối tượng. Mục tiêu của tôi là đảm bảo rằng một mảng (trong trường hợp này là "a") được truyền cho đối tượng cũng được sửa đổi. Vì vậy, tôi đang tìm kiếm một cách để nó in ra [1,2,3,4,5] –

+0

Tôi sẽ có một suy nghĩ rất cẩn thận về những gì bạn đang cố gắng làm ở đây. Bằng cách muốn sao chép nội dung của một mảng bên ngoài mỗi khi bạn thay đổi một biến mảng nội bộ, bạn đang hủy bỏ khái niệm 'đóng gói'. Nó sẽ không được tốt hơn để thao tác biến mảng nội bộ và sau đó phơi bày nó khi cần thiết? Tôi nghĩ rằng câu trả lời của Leo là thông minh bằng cách sử dụng sức mạnh của các nhà quan sát tài sản nhưng nó sao chép toàn bộ mảng mỗi khi một phần tử mảng được thay đổi. – timbo

+0

Tôi không đồng ý về việc đóng gói. Hãy nói rằng chúng tôi đã đi qua và đối tượng với Foo và Foo đã gọi một số phương pháp mà sẽ sửa đổi nội dung đối tượng này. Điều này sẽ không phá vỡ đóng gói. Nói chung Array là đối tượng. Chúng tôi đang gọi một phương pháp (phụ thêm) vào nó. Vì vậy, nó không nên được điều trị bất kỳ khác nhau. –

4

Bạn sẽ phải sử dụng NSArray hoặc NSMutableArray cho điều này vì Swift Arrays là các loại giá trị nên bất kỳ nhiệm vụ nào cũng sẽ tạo một bản sao.

0

a được khai báo là hằng số do đó không thể sửa đổi được. Nếu bạn đang có kế hoạch sửa đổi nội dung của một, khai báo nó như là một biến. ví dụ:

var a = [1,2,3,4] 
+0

Bạn nói đúng. a phải được khai báo là "var". Tuy nhiên, vấn đề còn sâu sắc hơn thế. –

1

Bạn có thể tận dụng Yến (rất un-Swifty) UnsafeMutablePointer.

Vì (từ bài đăng của bạn), tham chiếu hành vi đối với mảng không thực sự đáng tin cậy, thay vào đó hãy giữ UnsafeMutablePointer đồng hành với mảng bên trong lớp foo cũng như bất kỳ mảng "bên ngoài" nào bạn muốn được gắn với foo , theo nghĩa là cả hai chỉ là con trỏ đến cùng một địa chỉ trong bộ nhớ.

class Foo { 
    var foo : [Int] 
    var pInner: UnsafeMutablePointer<Int> 

    init(foo: [Int]) { 
     pInner = UnsafeMutablePointer(foo) 
     self.foo = Array(UnsafeBufferPointer(start: pInner, count: foo.count)) 
    } 

    func modify(inout pOuter: UnsafeMutablePointer<Int>) { 
     foo.append(5) // <-- foo gets new memory adress 
     pInner = UnsafeMutablePointer(foo) 
     pOuter = pInner 
    } 
} 

var a = [1,2,3,4] // first alloc in memory 
var pOuter: UnsafeMutablePointer<Int> = UnsafeMutablePointer(a) 
var bar = Foo(foo: a) // 'bar.foo' now at same address as 'a' 
print(bar.foo) // [1,2,3,4] 
bar.modify(&pOuter) // -> [1,2,3,4,5] 
a = Array(UnsafeBufferPointer(start: pOuter, count: bar.foo.count)) 

/* Same pointer adress, OK! */ 
print(bar.pInner) 
print(pOuter) 

/* Naturally same value (same address in memory) */ 
print(bar.foo) 
print(a) 

Con trỏ có thể gây nguy hiểm (do đó loại tên phù hợp) và, một lần nữa, rất không khéo léo. Dù sao...

/* When you're done: clear pointers. Usually when using 
    pointers like these you should take care to .destroy 
    and .dealloc, but here your pointers are just companions 
    to an Array property (which has a pointer an reference 
    counter itself), and the latter will take care of the 
    objects in memory when it goes out of scope.   */ 
bar.pInner = nil 
pOuter = nil 

Bây giờ, những gì xảy ra khi một trong hai a hoặc foo đi ra khỏi phạm vi, nó sẽ phá vỡ các biến mà không phải là ra khỏi phạm vi, hoặc không Swift chứa một số tính tham khảo thông minh mà nhận ra một địa chỉ bộ nhớ vẫn còn trong sử dụng ? Tôi đã không điều tra điều này, nhưng cảm thấy tự do để thưởng thức chính mình trong đó.

+0

Thú vị. Bạn sẽ phải vượt qua pOuter trong mỗi phương thức thay đổi mảng bên trong. –

+0

Vâng, nó không phải là giải pháp nhanh nhất hay đẹp nhất, nhưng bạn sẽ biết chắc chắn rằng các mảng của bạn không chỉ được "sửa đổi ở mọi nơi khác", nhưng trên thực tế, cùng một mảng trong bộ nhớ. Ngoài ra, lưu ý rằng đối với điểm A) trong câu trả lời của bạn: swift phân bổ chính xác không gian bạn cần khi khởi tạo một mảng với các giá trị. Nếu bạn chắp thêm một giá trị, nó cần phân bổ không gian cho mảng đầy đủ + phần tử mới ở nơi khác, sau đó sao chép mảng "cũ" + mục mới vào không gian mới, và cuối cùng giải phóng không gian cũ. Đây là lý do tại sao nó có vẻ như là nó ngẫu nhiên bằng cách sử dụng bản sao tham chiếu/giá trị. – dfri

Các vấn đề liên quan