Tüm alt görünümler kaldırılsın mı?


316

Uygulamam kök görünüm denetleyicisine geri döndüğünde, viewDidAppear:yöntemde tüm alt görünümleri kaldırmam gerekiyor.

Bunu nasıl yapabilirim?

Yanıtlar:


569

Düzenleme: kakaofan sayesinde : Bu durum gerçeği ile karıştırılır NSViewve UIViewfarklı şeyler ele. İçin NSView(sadece masaüstü Mac geliştirme), sadece aşağıdaki kullanabilirsiniz:

[someNSView setSubviews:[NSArray array]];

İçin UIView(yalnızca iOS geliştirme), güvenle kullanabilirsiniz makeObjectsPerformSelector:çünkü subviewsbu tesiste dönecektir kopyasını subviews dizisinin:

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

Tommy , numaralandırılırken diziyi makeObjectsPerformSelector:değiştirdiği anlaşılan işaret için teşekkür ederiz subviews(ki bunun için yapar NSView, ancak değil UIView).

Daha fazla ayrıntı için lütfen bu SO sorusuna bakın.

Not: Bu iki yöntemden herhangi biri kullanıldığında, ana görünümünüzün içerdiği her görünüm kaldırılır ve başka bir yerde saklanmazlarsa bu görünümler serbest bırakılır . Apple'ın removeFromSuperview ile ilgili belgelerinden :

Alıcının denetimi sıfır değilse, bu yöntem alıcıyı serbest bırakır. Görünümü yeniden kullanmayı planlıyorsanız, bu yöntemi çağırmadan önce koruduğunuzdan emin olun ve işiniz bittiğinde veya başka bir görünüm hiyerarşisine ekledikten sonra uygun şekilde bıraktığınızdan emin olun.


9
Bunun güvenli olduğundan emin misin? Listeyi yinelerken değiştirir ve Apple'ın belgelerinde kesin bir ifade bulamıyorum.
Tommy

8
@Tommy: Bu iyi bir nokta. Bazı Googling cevap geldi: UIViewdöner bir kopyası ait subviewsdeğişken dizisi bu kod sadece çalışır böylece. Aynı kodun bir istisna atacağı masaüstünde tamamen farklı bir hikaye. Bkz. Stackoverflow.com/questions/4665179/…
e.James

3
UIView, setSubviews yanıt vermiyor: değil mi?
cocoafan

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

3
@BenoitJadinon - derlenmeyecek - ForEach gerçekleştirmek için Tümü kötüye demek gibi görünüyor, yani someUIView.Subviews.All( v => { v.RemoveFromSuperview(); return true; } );. Ne demek istediğini söylemek için temizleyici someUIView.Subviews.ToList().ForEach( v => v.RemoveFromSuperview() );.
ToolmakerSteve

173

Kök denetleyicinizden tüm alt görünümleri alın ve her birine bir removeLromSuperview gönderin:

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

+1 ve teşekkür ederim. Ben de self.viewsenin gibi kullanmalıydım.
e.James

2
neden olmasın!? for (UIView *v in [self.view subviews])daha kolay
Frade

4
@Frade Yaptığı şekilde çok daha net ve daha ayrıntılı. Ayrıntılı ve okunabilirlik> tuş vuruşlarını kaydetme
taylorcressy

33
@taylorcressy "Okunabilirlik> tuş vuruşlarını kaydetme" yerine "okunabilirlik tuş vuruşlarını kaydetmekten daha önemli" demelisiniz ve yorumunuz daha okunabilir olacaktır. :-)
arlomedia

1
Unutmayalım ki, [self.view alt görünümleri] kaputun altında herhangi bir hesaplama yaparsa, doğrudan for döngüsüne koymak, bu hesaplamaların tekrar tekrar yapılmasına neden olabilir. Döngüden önce bildirilmesi, bunların yalnızca bir kez yapılmasını sağlar.
Brian Sachetta

116

In Swift bir kullanabilirsiniz işlevsel yaklaşım böyle:

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

Bir karşılaştırma olarak, zorunlu yaklaşım şöyle görünecektir:

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

Bu kod snippet'leri yalnızca iOS / tvOS'ta çalışır, ancak macOS'ta işler biraz farklıdır.


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

8
bir işlev bir değer döndürdüğünden işlevsel değildir ve bu sadece sonucunu atar .map. Bu saf bir yan etkidir ve daha iyi şu şekilde ele alınır:view.subviews.forEach() { $0.removeFromSuperview() }
Martin Algesten

1
Haklısın Martin, sana katılıyorum. Dizilerde bir forEach () yöntemi olduğunu bilmiyordum. Ne zaman eklendi veya sadece denetledim mi? Cevabımı güncelledim!
Jeehut

1
O kadar tembelim ki, alt görünümleri nasıl temizleyeceğimi bilsem bile, hala buraya snippet'inizi kopyalamak / yapıştırmak ve +1
Vilmir

13

UIView'inizdeki tüm alt görünümleri kaldırmak istiyorsanız (burada yourView), bu düğmeyi düğme tıklamanıza yazın:

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

12
Stack Overflow'a hoş geldiniz! Bu kodun neden işe yaradığını ve soruyu sorunun cevabı haline getiren açıklamayı eklemeyi düşünür müsünüz? Bu, soruyu soran kişiye ve birlikte gelen herkese çok yardımcı olacaktır. Ayrıca, zaten kabul edilen cevap, esas olarak bununla aynı olan kodu içerir.
Andrew Barber

5
Bu, kabul edilen cevaptan daha çok nasıl yardımcı olabilir: Özdeş. Bunu neden yazıyorsunuz?
Rambatino

8

İOS'ta dizinin bir kopyası tutulduğu için bu yalnızca OSX için geçerlidir

Tüm alt görünümleri kaldırırken, dizinin sonunda silmeye başlamak ve siz başlangıca ulaşıncaya kadar silmeye devam etmek iyi bir fikirdir. Bu, bu iki kod satırı ile gerçekleştirilebilir:

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

SWIFT 1.2

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

veya (daha az verimli, ancak daha okunabilir)

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

NOT

Sen gerektiğini DEĞİL önce UIView örneği silinirse o çökmesine neden olabileceğinden, normal sırada subviews kaldırmak removeFromSuperviewmesaj dizinin tüm nesnelere gönderildi. (Açıkçası, son öğenin silinmesi çökmeye neden olmaz)

Bu nedenle, kod

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

gerektiğini DEĞİL kullanılan olabilir.

Dan alıntı makeObjectsPerformSelector hakkında Elma belgelerinde :

Dizideki her bir nesneye, ilk nesneden başlayarak ve dizi boyunca son nesneye devam ederek belirli bir seçici tarafından tanımlanan iletiyi gönderir.

(bu amaç için yanlış yön olur)


Ne kastettiğinize bir örnek verebilir misiniz? Ne "element" olarak adlandırdığınız bilmiyorum Ve removeFromSuperView çağırmadan önce bu öğeler nasıl kaldırılır?
Muhterem

Ancak bu yöntemi çağırırken bir UIView örneği nasıl silinebilir? Alt görünüm dizisinden kaldırılmayı mı kastediyorsunuz?
Aziz

Tamamlandığında removeFromSuperview, UIView diziden kaldırılır ve UIView ile güçlü bir ilişkisi olan başka canlı örnek yoksa UIView de silinir. Bu, sınır dışı bir istisnaya neden olabilir.
Daniel

1
Anladım! Teşekkür ederim. Sanırım IOS'taki alt görünüm dizisinin bir kopyasını alıyorsunuz. Her durumda, alt görünümleri kaldırmak istiyorsanız kendiniz bir kopyasını oluşturmak iyi bir fikir olacaktır.
Aziz

@simpleBob - 2011 yılında kabul edilen cevap üzerine yazılan yorumları okudunuz mu? Bu yorumlara göre, iOS'ta [yourView subviews]dizinin bir KOPYASINI döndürüyor, bu nedenle güvenlidir. (OSX'te söylediklerinizin doğru olduğunu unutmayın.)
ToolmakerSteve

4

Bu şekilde hızlı 2.0 deneyin

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

2
Daha önce olduğum tarihi cevaplama tarihini görmüyor musunuz? Cevap bağlantımı neden bu cevaba yapıştırmıyorsunuz?
William Hu

1
Doğru ... cevap sizinkinden önce gönderildi, ancak forEachtemel çözüm sizinkinden sonra eklendi, bunu kaçırdım. Özür.
Cristik

4

Tüm alt görünümleri kaldırmak için Aşağıdaki kodu kullanın.

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

2

Swift UIViewuzantısını kullanma :

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

2

Hedef-C'de devam edin ve UIView sınıfından bir kategori yöntemi oluşturun.

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

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

2
Bu kod soruyu cevaplayabilirken, sorunun nasıl ve / veya neden çözüldüğüne dair ek bağlam sağlamak yanıtlayıcının uzun vadeli değerini artıracaktır.
Nic3500

1

Tüm alt görünümleri sözdizimini kaldırmak için:

- (void)makeObjectsPerformSelector:(SEL)aSelector;

Kullanımı:

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

Bu yöntem NSArray.h dosyasında bulunur ve NSArray (NSExtendedArray) arabirimini kullanır


1

Swift kullanıyorsanız, bu kadar basit:

subviews.map { $0.removeFromSuperview }

Felsefede makeObjectsPerformSelectoryaklaşımla benzerdir , ancak biraz daha güvenlikle.


Bu anlamsal olarak yanlıştır, mapyan etkilere neden olmamalıdır. Ayrıca, aynı sonuç üzerinden de elde edilebilir forEach.
Cristik

0

Autolayout kullanan ios6 için de kısıtlamaları kaldırmak için biraz kod eklemek zorunda kaldım.

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)];

Eminim bunu yapmanın daha temiz bir yolu var, ama benim için çalıştı. Benim durumumda [tagview removeConstraints:tagview.constraints]XCode'da temizlenen kısıtlamalar olduğu için doğrudan kullanamadım .


0

Monotouch / xamarin.ios'ta bu benim için çalıştı:

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

-10

Tüm alt görünümleri denetim ekranlarından kaldırmak için:

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

Birkaç büyük hata @Pravin. İlk olarak, 'nesne'nin bir UIView * olarak tanımlanması gerekir, aksi takdirde [object removeFromSuperview] ile derleyici hatası alırsınız. İkinci olarak, for döngünüz zaten iCount'u azaltıyor, bu nedenle iCount-- satırınızla fazladan bir atlama yapıyorsunuz. Ve son olarak, yukarıda iki çalışma ve doğru yaklaşım vardır ve sizinki ne daha zarif ne de daha hızlıdır.
amergin

5
yaptığınız her yineleme iCount++ve iCount--dizini aynı bırakarak, eğer sonsuz bir döngü olacaktır [oSubView count]>0. Bu kesinlikle buggy ve DEĞİL KULLANILABİLİR kodu.
Daniel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.