Xóa tất cả các cuộc phỏng vấn?


316

Khi ứng dụng của tôi quay lại trình điều khiển xem gốc, trong viewDidAppear:phương thức tôi cần xóa tất cả các lần xem.

Tôi có thể làm cái này như thế nào?

Câu trả lời:


569

Chỉnh sửa: Nhờ có cocoafan : Tình huống này được xử lý bằng thực tế NSViewUIViewxử lý mọi việc khác nhau. Đối với NSView(chỉ phát triển máy tính để bàn), bạn chỉ cần sử dụng như sau:

[someNSView setSubviews:[NSArray array]];

Đối với UIView(chỉ phát triển iOS), bạn có thể sử dụng một cách an toàn makeObjectsPerformSelector:vì thuộc subviewstính sẽ trả về một bản sao của mảng các cuộc phỏng vấn:

[[someUIView subviews]
 makeObjectsPerformSelector:@selector(removeFromSuperview)];

Cảm ơn Tommy vì đã chỉ ra rằng có makeObjectsPerformSelector:vẻ như sửa đổi subviewsmảng trong khi nó đang được liệt kê (cái này làm NSView, nhưng không phải cho UIView).

Xin vui lòng xem câu hỏi SO này để biết thêm chi tiết.

Lưu ý: Sử dụng một trong hai phương pháp này sẽ xóa mọi chế độ xem mà chế độ xem chính của bạn chứa và giải phóng chúng , nếu chúng không được giữ lại ở nơi khác. Từ tài liệu của Apple về removeFromSuperview :

Nếu giám sát của người nhận không bằng không, phương pháp này sẽ giải phóng người nhận. Nếu bạn có kế hoạch sử dụng lại chế độ xem, hãy chắc chắn giữ lại trước khi gọi phương thức này và chắc chắn phát hành nó khi thích hợp khi bạn thực hiện với nó hoặc sau khi thêm nó vào hệ thống phân cấp chế độ xem khác.


9
Bạn có chắc chắn điều này là an toàn? Nó làm thay đổi danh sách trong khi lặp lại nó và tôi không thể tìm thấy một tuyên bố dứt khoát trong tài liệu của Apple.
Tommy

8
@ Mẹ: Đó là một điểm tốt. Một số Googling đã đưa ra câu trả lời: UIViewtrả về một bản sao của subviewsmảng có thể thay đổi, vì vậy mã này chỉ hoạt động. Câu chuyện hoàn toàn khác nhau trên máy tính để bàn, trong đó cùng một mã sẽ đưa ra một ngoại lệ. Xem stackoverflow.com/questions/4665179/
Mạnh

3
UIView không trả lời setSubview:, phải không?
cocoafan

4
cách Xamarin: someUIView.Subviews.All (p => p.RemoveFromSuperview);
Benoit Jadinon

3
@BenoitJadinon - sẽ không biên dịch - bạn dường như lạm dụng Tất cả để thực hiện ForEach, vì vậy someUIView.Subviews.All( v => { v.RemoveFromSuperview(); return true; } );. IMHO sạch hơn để nói những gì bạn có nghĩa là : someUIView.Subviews.ToList().ForEach( v => v.RemoveFromSuperview() );.
ToolmakerSteve

173

Nhận tất cả các cuộc phỏng vấn từ bộ điều khiển gốc của bạn và gửi cho mỗi removeFromSuperview:

NSArray *viewsToRemove = [self.view subviews];
for (UIView *v in viewsToRemove) {
    [v removeFromSuperview];
}

+1 và cảm ơn bạn. Tôi cũng nên sử dụng self.viewnhư bạn có.
e.James

2
tại sao không!? for (UIView *v in [self.view subviews])nó dễ dàng hơn
Frade

4
@Frade Thật rõ ràng và dài dòng hơn nhiều so với cách anh ấy đã làm. Verbose và khả năng đọc> lưu tổ hợp phím
taylorcressy

33
@taylorcressy Bạn nên nói "khả năng đọc quan trọng hơn việc lưu tổ hợp phím" thay vì "khả năng đọc> lưu tổ hợp phím" và sau đó nhận xét của bạn sẽ dễ đọc hơn. :-)
arlomedia

1
Chúng ta đừng quên thực tế là nếu [các cuộc phỏng vấn self.view] thực hiện bất kỳ phép tính nào dưới mui xe, việc đặt nó trực tiếp vào vòng lặp for có thể khiến các phép tính đó được thực hiện lặp đi lặp lại. Khai báo nó trước vòng lặp đảm bảo chúng chỉ được thực hiện một lần.
Brian Sachetta

116

Trong Swift, bạn có thể sử dụng một cách tiếp cận chức năng như thế này:

view.subviews.forEach { $0.removeFromSuperview() }

Để so sánh, cách tiếp cận bắt buộc sẽ như thế này:

for subview in view.subviews {
    subview.removeFromSuperview()
}

Các đoạn mã này chỉ hoạt động trong iOS / tvOS , mọi thứ hơi khác một chút trên macOS.


4
(subviews as [UIView]).map { $0.removeFromSuperview() }
DeFrenZ

8
nó không hoạt động vì một hàm trả về một giá trị và điều này chỉ loại bỏ kết quả của .map. Đây là một tác dụng phụ thuần túy và được xử lý tốt hơn như thế này:view.subviews.forEach() { $0.removeFromSuperview() }
Martin Algesten

1
Bạn nói đúng, Martin, tôi đồng ý với bạn. Tôi chỉ không biết có một phương thức forEach () trên Mảng. Khi nào nó được thêm vào hoặc tôi chỉ giám sát nó? Tôi đã cập nhật câu trả lời của mình!
Jeehut

1
Tôi lười đến nỗi ngay cả khi tôi biết cách xóa các cuộc phỏng vấn, tôi vẫn đến đây để sao chép / dán đoạn trích của bạn và đặt +1
Vilmir

13

Nếu bạn muốn xóa tất cả các cuộc phỏng vấn trên UIView của bạn (tại đây yourView), sau đó viết mã này vào nút của bạn, nhấp:

[[yourView subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];

12
Chào mừng bạn đến với Stack Overflow! Bạn có xem xét việc thêm một số tường thuật để giải thích tại sao mã này hoạt động không, và điều gì làm cho nó trở thành một câu trả lời cho câu hỏi? Điều này sẽ rất hữu ích cho người đặt câu hỏi và bất kỳ ai khác đi cùng. Ngoài ra, câu trả lời đã được chấp nhận bao gồm mã về cơ bản giống như mã này.
Andrew Barber

5
Làm thế nào điều này có thể giúp nhiều hơn so với câu trả lời được chấp nhận: Nó giống hệt nhau. Tại sao lại viết cái này?
Rambatino

8

Điều này chỉ áp dụng cho OSX vì trong iOS, một bản sao của mảng được giữ

Khi xóa tất cả các cuộc phỏng vấn, một ý tưởng tốt là bắt đầu xóa ở cuối mảng và tiếp tục xóa cho đến khi bạn đạt đến điểm bắt đầu. Điều này có thể được thực hiện với hai dòng mã này:

for (int i=mySuperView.subviews.count-1; i>=0; i--)
        [[mySuperView.subviews objectAtIndex:i] removeFromSuperview];

Chuyển đổi 1.2

for var i=mySuperView.subviews.count-1; i>=0; i-- {
    mySuperView.subviews[i].removeFromSuperview();
}

hoặc (ít hiệu quả hơn, nhưng dễ đọc hơn)

for subview in mySuperView.subviews.reverse() {
    subview.removeFromSuperview()
}

GHI CHÚ

Bạn KHÔNG nên xóa các cuộc phỏng vấn theo thứ tự thông thường, vì nó có thể gây ra sự cố nếu một đối tượng UIView bị xóa trước khiremoveFromSuperview tin nhắn được gửi đến tất cả các đối tượng của mảng. (Rõ ràng, xóa phần tử cuối cùng sẽ không gây ra sự cố)

Do đó, mã

[[someUIView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

KHÔNG nên được sử dụng.

Trích dẫn từ tài liệu của Apple về makeObjectsPerformSelector :

Gửi đến từng đối tượng trong mảng thông điệp được xác định bởi một bộ chọn đã cho, bắt đầu với đối tượng đầu tiên và tiếp tục thông qua mảng đến đối tượng cuối cùng.

(đó sẽ là hướng đi sai cho mục đích này)


Bạn có thể vui lòng làm một ví dụ về những gì bạn đang đề cập đến? Không biết những gì bạn đang đề cập đến như là "phần tử" Và làm thế nào các phần tử này sẽ bị xóa trước khi gọi removeFromSuperView?
Reverend

Nhưng làm thế nào một thể hiện của UIView có thể bị xóa trong khi gọi phương thức này? Bạn có nghĩa là loại bỏ khỏi mảng subview?
Reverend

Khi removeFromSuperviewkết thúc, UIView sẽ bị xóa khỏi mảng và nếu không có trường hợp sống nào khác có mối quan hệ chặt chẽ với UIView, UIView cũng sẽ bị xóa. Điều này có thể gây ra một ngoại lệ ràng buộc.
Daniel

1
Gotcha! Cảm ơn bạn. Tôi nghĩ rằng bạn đang nhận được một bản sao của mảng xem trước trên iOS. Trong mọi trường hợp, sẽ là một ý tưởng tốt để tự tạo một bản sao nếu bạn muốn xóa các cuộc phỏng vấn.
Reverend

@simpleBob - bạn đã đọc những bình luận viết năm 2011 về câu trả lời được chấp nhận chưa? Theo những bình luận đó, trên iOS, [yourView subviews]trả về một BẢN SAO của mảng, do đó an toàn. (LƯU Ý rằng trên OSX, những gì bạn nói là chính xác.)
ToolmakerSteve

4

Hãy thử cách này nhanh chóng 2.0

view.subviews.forEach { $0.removeFromSuperview() }

2
Bạn không thấy ngày trả lời ngày tôi đến sớm hơn? Tại sao không dán liên kết câu trả lời của tôi vào câu trả lời đó?
William Hu

1
Phải ... câu trả lời đã được đăng trước bạn, tuy nhiên forEachgiải pháp dựa trên đã được thêm vào sau bạn, tôi đã bỏ lỡ điều đó. Lời xin lỗi.
Cristik

4

Sử dụng mã sau đây để loại bỏ tất cả các cuộc phỏng vấn.

for (UIView *view in [self.view subviews]) 
{
 [view removeFromSuperview];
}

2

Sử dụng UIViewtiện ích mở rộng Swift :

extension UIView {
    func removeAllSubviews() {
        for subview in subviews {
            subview.removeFromSuperview()
        }
    }
}

2

Trong mục tiêu-C, hãy tiếp tục và tạo một phương thức thể loại khỏi lớp UIView.

- (void)removeAllSubviews
{
    for (UIView *subview in self.subviews)
        [subview removeFromSuperview];
}

2
view.subviews.forEach { $0.removeFromSuperview() }

2
Mặc dù mã này có thể trả lời câu hỏi, việc cung cấp ngữ cảnh bổ sung về cách thức và / hoặc lý do giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Nic3500

1

Để xóa tất cả các cuộc phỏng vấn Cú pháp:

- (void)makeObjectsPerformSelector:(SEL)aSelector;

Sử dụng :

[self.View.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

Phương thức này có trong tệp NSArray.h và sử dụng giao diện NSArray (NSExtendsArray)


1

Nếu bạn đang sử dụng Swift, nó đơn giản như:

subviews.map { $0.removeFromSuperview }

Về mặt triết học, nó tương tự như makeObjectsPerformSelectorcách tiếp cận, tuy nhiên với sự an toàn hơn một chút.


Điều này là không chính xác về mặt ngữ nghĩa, mapkhông nên dẫn đến tác dụng phụ. Thêm vào đó, kết quả tương tự có thể đạt được thông qua forEach.
Cristik

0

Đối với ios6 bằng cách sử dụng tự động thanh toán, tôi đã phải thêm một chút mã để loại bỏ các ràng buộc.

NSMutableArray * constraints_to_remove = [ @[] mutableCopy] ;
for( NSLayoutConstraint * constraint in tagview.constraints) {
    if( [tagview.subviews containsObject:constraint.firstItem] ||
       [tagview.subviews containsObject:constraint.secondItem] ) {
        [constraints_to_remove addObject:constraint];
    }
}
[tagview removeConstraints:constraints_to_remove];

[ [tagview subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

Tôi chắc chắn có một cách gọn gàng hơn để làm điều này, nhưng nó hiệu quả với tôi. Trong trường hợp của tôi, tôi không thể sử dụng trực tiếp [tagview removeConstraints:tagview.constraints]vì có các ràng buộc được đặt trong XCode đang bị xóa.


0

Trong monotouch / xamarin.ios, điều này làm việc cho tôi:

SomeParentUiView.Subviews.All(x => x.RemoveFromSuperview);

-10

Để xóa tất cả các cuộc phỏng vấn khỏi giám sát:

NSArray *oSubView = [self subviews];
for(int iCount = 0; iCount < [oSubView count]; iCount++)
{
    id object = [oSubView objectAtIndex:iCount];
    [object removeFromSuperview];
    iCount--;
}

Vài lỗi chính ở đây @Pravin. Trước tiên, bạn cần xác định 'đối tượng' là UIView * nếu không, bạn sẽ gặp lỗi trình biên dịch với [object removeFromSuperview]. Thứ hai, vòng lặp for của bạn đã giảm iCount vì vậy bạn đang bỏ qua một vòng bổ sung với dòng iCount-- của bạn. Và cuối cùng, có hai cách tiếp cận đúng và hiệu quả ở trên và cách tiếp cận của bạn không thanh lịch hơn cũng không nhanh hơn.
amergin

5
mỗi lần lặp bạn làm iCount++iCount--, để lại chỉ mục giống nhau, vì vậy nó sẽ là một vòng lặp vô hạn nếu [oSubView count]>0. Đây chắc chắn là lỗi và mã KHÔNG CÓ .
Daniel
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.