Nhập kiểu đúc trong vòng lặp for-in


116

Tôi có vòng lặp for-in này:

for button in view.subviews {
}

Bây giờ tôi muốn nút được chuyển thành một lớp tùy chỉnh để tôi có thể sử dụng các thuộc tính của nó.

Tôi đã thử điều này: for button in view.subviews as AClass

Nhưng nó không hoạt động và cho tôi một lỗi:'AClass' does not conform to protocol 'SequenceType'

Và tôi đã thử điều này: for button:AClass in view.subviews

Nhưng nó không hoạt động.


Làm thế nào vềfor button in view.subviews as [AClass]
vacawama

2
haha Tôi đã không nghĩ về điều đó, tất nhiên tốt hơn là nên chuyển mảng thành một mảng của AClass, cảm ơn người đàn ông. Bạn có thể đưa ra câu trả lời về nó để tôi có thể cung cấp cho bạn một số đại diện :)
Arbitur

Câu trả lời:


173

Dành cho Swift 2 trở lên:

Swift 2 cho biết thêm mô hình trường hợp để cho vòng, mà làm cho nó thậm chí còn dễ dàng hơn và an toàn hơn để gõ dàn diễn viên trong một cho vòng lặp:

for case let button as AClass in view.subviews {
    // do something with button
}

Tại sao điều này tốt hơn những gì bạn có thể làm trong Swift 1.2 trở về trước? Bởi vì các mẫu trường hợp cho phép bạn chọn loại cụ thể của bạn ra khỏi bộ sưu tập. Nó chỉ phù hợp với loại bạn đang tìm kiếm, vì vậy nếu mảng của bạn chứa hỗn hợp, bạn chỉ có thể hoạt động trên một loại cụ thể.

Ví dụ:

let array: [Any] = [1, 1.2, "Hello", true, [1, 2, 3], "World!"]
for case let str as String in array {
    print(str)
}

Đầu ra:

Hello
World!

Dành cho Swift 1.2 :

Trong trường hợp này, bạn đang truyền view.subviewsvà không button, vì vậy bạn cần hạ thấp nó xuống mảng của loại bạn muốn:

for button in view.subviews as! [AClass] {
    // do something with button
}

Lưu ý: Nếu loại mảng cơ bản là không [AClass], điều này sẽ sụp đổ. Đó là những gì !trên as!đang nói với bạn. Nếu bạn không chắc chắn về loại bạn có thể sử dụng dàn diễn viên có điều kiện as?cùng với ràng buộc tùy chọn if let:

if let subviews = view.subviews as? [AClass] {
    // If we get here, then subviews is of type [AClass]
    for button in subviews {
        // do something with button
    }
}

Đối với Swift 1.1 trở về trước:

for button in view.subviews as [AClass] {
    // do something with button
}

Lưu ý: Điều này cũng sẽ sụp đổ nếu các cuộc phỏng vấn không phải là tất cả các loại AClass. Phương pháp an toàn được liệt kê ở trên cũng hoạt động với các phiên bản trước của Swift.


Chỉ là một lưu ý cho những người khác như tôi lúc đầu không nhận được nó - tên lớp phải đi vào trong [ ]ngoặc chính xác như trong ví dụ này. Có thể đó chỉ là tôi nhưng tôi nghĩ ban đầu nó chỉ là một lựa chọn định dạng trong mẫu mã :) Tôi cho rằng điều này là do chúng tôi đang chuyển sang một mảng.

@kmcgrady Nó chỉ [Class]đẹp hơn nhiều Array<Class>.
Arbitur 14/07/2015

Vì vậy, vì tò mò, có cách nào để thực hiện nhiều câu lệnh tình huống bên trong vòng lặp for không? Nếu tôi muốn làm một điều với các nút, một điều khác cho các trường văn bản?
RonLugge

125

Tùy chọn này an toàn hơn:

for case let button as AClass in view.subviews {
}

hoặc cách khéo léo:

view.subviews
  .compactMap { $0 as AClass }
  .forEach { .... }

1
Điều này có vẻ như câu trả lời đẹp hơn vì không có lực lượng đúc.
Patrick

1
Đây phải là câu trả lời được chấp nhận. Là một trong những tốt nhất và chính xác!
Thomás Calmon

Câu trả lời chính xác. Ngắn gọn và đơn giản.
PashaN

4

Bạn cũng có thể sử dụng một wheremệnh đề

for button in view.subviews where button is UIButton {
    ...
}

12
Mệnh đề where là một bảo vệ boolean, nhưng không bỏ kiểu buttonbên trong thân vòng lặp, đó là mục tiêu của các giải pháp khác. Vì vậy, điều này sẽ chỉ chạy phần thân vòng lặp trên các phần tử view.subviewsUIButtons, nhưng không giúp ích gì, ví dụ như trong việc gọi AClasscác phương thức cụ thể trên button.
John Whitley

1
@JohnWhitley bạn đúng là wherechỉ bảo vệ và không bỏ vai.
edelaney05

wherecó thể thanh lịch hơn và dễ đọc hơn đối với các trường hợp (chơi chữ không chủ ý) khi bạn chỉ cần một người bảo vệ boolean.
STO

3

Các câu trả lời được cung cấp là chính xác, tôi chỉ muốn thêm điều này như là một bổ sung.

Khi sử dụng vòng lặp for với ép buộc, mã sẽ bị sập (như đã được đề cập bởi những người khác).

for button in view.subviews as! [AClass] {
    // do something with button
}

Nhưng thay vì sử dụng mệnh đề if,

if let subviews = view.subviews as? [AClass] {
    // If we get here, then subviews is of type [AClass]
    ...
}

một cách khác là sử dụng vòng lặp while:

/* If you need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let (index, subview) = iterator.next() as? (Int, AClass) {
    // Use the subview
    // ...
}

/* If you don't need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let subview = iterator.next().element as? AClass {
    // Use the subview
    // ...
}

Điều này có vẻ thuận tiện hơn nếu một số phần tử (nhưng không phải tất cả) của mảng có thể thuộc loại AClass.

Mặc dù bây giờ (kể từ Swift 5), tôi sẽ đi theo vòng lặp for:

for case let (index, subview as AClass) in view.subviews.enumerated() {
    // ...
}

for case let subview as AClass in view.subviews {
    // ...
}

Chỉ có một nghi ngờ ở đây ... chức năng liệt kê nhanh chóng thực hiện các lần lặp / vòng lặp ở đây .. chỉ nghĩ tái cấu trúc cho việc mất hiệu suất sẽ không tuyệt vời ... cảm ơn
Amber K

2

Câu trả lời được cung cấp bởi vacawama là chính xác trong Swift 1.0. Và không còn hoạt động với Swift 2.0.

Nếu bạn thử, bạn sẽ gặp một lỗi tương tự như:

'[AnyObject]' không thể chuyển đổi thành '[AClass]';

Trong Swift 2.0, bạn cần viết như sau:

for button in view.subviews as! [AClass]
{
}

0

Bạn có thể thực hiện việc đúc và an toàn cùng một lúc với điều này:

for button in view.subviews.compactMap({ $0 as? AClass }) {

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.