모든 서브 뷰를 제거 하시겠습니까?


316

내 앱이 루트보기 컨트롤러로 돌아 오면 viewDidAppear:메소드 에서 모든 하위보기를 제거해야합니다.

어떻게해야합니까?

답변:


569

편집은 : 덕분으로 cocoafan :이 상황은 그 사실에 의해 뒤죽박죽되어 NSViewUIView핸들 것을 다르게. 들어 NSView(전용 데스크톱 맥 개발), 당신은 단순히 다음을 사용할 수 있습니다 :

[someNSView setSubviews:[NSArray array]];

들어 UIView(iOS 만 개발), 안전하게 사용할 수 makeObjectsPerformSelector:때문에 subviews속성이 반환됩니다 사본 파단의 배열을 :

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

배열이 열거되는 동안 배열 을 수정 하는 것처럼 보이는 것에 대해 Tommy 에게 감사드립니다 ( 하지만하지는 않습니다 ).makeObjectsPerformSelector:subviewsNSViewUIView

자세한 내용은 이 SO 질문 을 참조하십시오.

참고 : 이 두 가지 방법 중 하나를 사용하면 기본보기에 포함 된 모든보기가 제거되고 다른 위치에 유지되지 않으면 해제됩니다 . removeFromSuperview 에 관한 Apple 문서에서 :

수신자의 superview가 nil이 아닌 경우,이 메소드는 수신자를 해제합니다. 뷰를 재사용하려는 경우이 메소드를 호출하기 전에 뷰를 유지하고 뷰를 완료하거나 다른 뷰 계층 구조에 추가 한 후 적절하게 해제하십시오.


9
이것이 안전합니까? 목록을 반복하는 동안 목록을 변경하고 Apple 설명서에서 명확한 진술을 찾을 수 없습니다.
Tommy

8
@ 토미 : 좋은 지적입니다. 일부 인터넷 검색에서 답을 찾았습니다. 변경 가능한 배열 UIView사본 을 반환 subviews하므로이 코드는 작동합니다. 데스크톱에서 완전히 다른 이야기. 동일한 코드에서 예외가 발생합니다. 참조 stackoverflow.com/questions/4665179/...
e.James

3
UIView가 setSubviews에 응답하지 않습니다.
cocoafan

4
Xamarin 방식 : someUIView.Subviews.All (p => p.RemoveFromSuperview);
Benoit Jadinon 2016 년

3
@BenoitJadinon-컴파일하지 않습니다-모두 ForEach를 수행하기 위해 모두 학대하는 것을 의미 someUIView.Subviews.All( v => { v.RemoveFromSuperview(); return true; } );합니다. IMHO는 당신이 의미하는 바를 말하십시오 someUIView.Subviews.ToList().ForEach( v => v.RemoveFromSuperview() );.
ToolmakerSteve

173

루트 컨트롤러에서 모든 하위 뷰를 가져와 각각 removeFromSuperview를 보냅니다.

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

+1하고 감사합니다. 나는 또한 self.view당신이 가진 것처럼 사용해야합니다 .
e.James

2
왜 안돼!? for (UIView *v in [self.view subviews])쉬움
Frade

4
@Frade 그가하는 방식이 훨씬 더 명확하고 장황합니다. 자세한 정보 및 가독성> 키 입력 절약
taylorcressy

33
@taylorcressy "가독성> 키 스트로크 저장"대신 "키 스트로크를 저장하는 것보다 가독성이 중요하다"고 말한 다음에는 댓글을보다 읽기 쉽게 설명해야합니다. :-)
arlomedia

1
[self.view subviews]가 후드 아래에서 계산을 수행하는 경우 for 루프에 직접 넣으면 이러한 계산이 반복해서 수행 될 수 있다는 사실을 잊지 마십시오. 루프 전에 선언하면 한 번만 수행됩니다.
Brian Sachetta

116

Swift 에서는 다음 과 같은 기능적 접근 방식을 사용할 수 있습니다 .

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

이에 비해 명령 방식 은 다음과 같습니다.

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

이 코드 스 니펫은 iOS / tvOS 에서만 작동 하지만 macOS에서는 상황이 약간 다릅니다.


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

8
함수가 값을 반환하기 때문에 작동하지 않으며 이것은 단지 결과를 버립니다 .map. 이것은 순수한 부작용이며 다음과 같이 처리하는 것이 좋습니다.view.subviews.forEach() { $0.removeFromSuperview() }
Martin Algesten

1
당신 말이 맞아요, 마틴 동의합니다 배열에 forEach () 메소드가 있다는 것을 몰랐습니다. 언제 추가했거나 방금 감독 했습니까? 내 답변을 업데이트했습니다!
Jeehut

1
나는 분명 파단에, 나는 여전히 +1 복사 / 당신의 조각을 붙여 넣어 여기 온 방법을 알고 있더라도 너무 게으른
Vilmir

13

UIView (여기에서 yourView)의 모든 하위보기를 제거하려면 버튼 클릭 시이 코드를 작성하십시오.

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

12
스택 오버플로에 오신 것을 환영합니다! 이 코드가 작동하는 이유를 설명하기 위해 설명을 추가하고 질문에 대한 대답은 무엇입니까? 이것은 질문하는 사람과 함께 오는 다른 사람에게 매우 도움이 될 것입니다. 또한 이미 받아 들여진 대답에는 본질적으로 이와 동일한 코드가 포함됩니다.
Andrew Barber

5
이것이 허용 된 답변보다 더 많은 도움을 줄 수있는 방법은 동일합니다. 왜 이것을 쓰나요?
Rambatino

8

iOS에서는 어레이의 사본이 유지되므로 OSX에만 적용됩니다.

모든 서브 뷰를 제거 할 때 배열의 끝에서 삭제를 시작하고 시작 부분에 도달 할 때까지 삭제를 유지하는 것이 좋습니다. 이 두 줄의 코드로 수행 할 수 있습니다.

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

스위프트 1.2

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

또는 (효율적이지 않지만 더 읽기 쉬운)

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

노트

당신은해야 하지 전과 UIView의 인스턴스가 삭제 된 경우는 충돌을 일으킬 수 있기 때문에, 정상적인 순서로 파단을 제거 removeFromSuperview메시지가 배열의 모든 객체로 전송되었습니다. (마지막으로 마지막 요소를 삭제하면 충돌이 발생하지 않습니다)

따라서 코드

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

해야 하지 사용합니다.

makeObjectsPerformSelector에 대한 Apple 문서 에서 인용하십시오 .

첫 번째 개체부터 시작하여 마지막 개체까지 배열을 통해 지정된 선택기로 식별 된 메시지를 배열의 각 개체로 보냅니다.

(이 목적을 위해 잘못된 방향이 될 것입니다)


당신이 말하는 것을 예를 들어 주시겠습니까? 무엇을 "요소"라고 부르는지 모르고 removeFromSuperView를 호출하기 전에이 요소를 어떻게 제거 하시겠습니까?
목사

그러나이 메소드를 호출하는 동안 UIView 인스턴스를 어떻게 삭제할 수 있습니까? 하위 뷰 배열에서 제거 했습니까?
목사

removeFromSuperview마감이는 UIView의 배열에서 제거됩니다있는 UIView에 강력한 관계와 다른 생활 인스턴스가없는 경우, 그리고, UIView의도 삭제됩니다. 이로 인해 범위를 벗어난 예외가 발생할 수 있습니다.
Daniel

1
잡았다! 감사합니다. 나는 당신이 IOS에서 subviews 배열의 사본을 얻고 있다고 생각합니다. 어쨌든 하위 뷰를 제거하려면 직접 사본을 만드는 것이 좋습니다.
목사

@simpleBob-2011 년에 작성된 답변에 대한 의견을 읽었습니까? 이러한 의견에 따르면 iOS에서는 [yourView subviews]배열의 COPY를 반환하므로 안전합니다. (OSX에서는 여러분이하는 말이 맞습니다.)
ToolmakerSteve

4

이 방법으로 스위프트 2.0을 사용해보십시오

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

2
이전 날짜의 응답 날짜가 보이지 않습니까? 답변 링크를 해당 답변에 붙여 넣지 않는 이유는 무엇입니까?
William Hu

1
맞아 ... 답은 당신 앞에 게시되었지만 forEach기반 솔루션은 당신 뒤에 추가 되었지만 , 나는 그것을 놓쳤다. 사과.
Cristik

4

모든 하위 뷰를 제거하려면 다음 코드를 사용하십시오.

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

2

스위프트 UIView확장 사용하기 :

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

2

objective-C에서 UIView 클래스에서 범주 메서드를 만듭니다.

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

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

2
이 코드는 질문에 대답 할 수 있지만 문제를 해결하는 방법 및 / 또는 이유에 대한 추가 컨텍스트를 제공하면 답변의 장기적인 가치가 향상됩니다.
Nic3500

1

모든 서브 뷰를 제거하려면 구문 :

- (void)makeObjectsPerformSelector:(SEL)aSelector;

사용법 :

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

이 메소드는 NSArray.h 파일에 존재하며 NSArray (NSExtendedArray) 인터페이스를 사용합니다.


1

Swift를 사용하는 경우 다음과 같이 간단합니다.

subviews.map { $0.removeFromSuperview }

철학적으로 makeObjectsPerformSelector접근 방식 과 비슷 하지만 조금 더 유형 안전성이 있습니다.


이것은 의미 상 올바르지 map않으며 부작용이 없어야합니다. 또한을 통해 동일한 결과를 얻을 수 있습니다 forEach.
Cristik

0

자동 레이아웃을 사용하는 ios6의 경우 제약 조건을 제거하기 위해 약간의 코드를 추가해야했습니다.

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

나는 이것을 할 수있는 더 좋은 방법이 있다고 확신하지만 그것은 나를 위해 일했다. 내 경우에는 직접 사용할 수 없습니다[tagview removeConstraints:tagview.constraints] XCode에 제약 조건이 설정되어 있기 때문에 을 습니다.


0

monotouch / xamarin.ios에서 이것은 나를 위해 일했습니다 :

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

-10

슈퍼 뷰에서 모든 서브 뷰를 제거하려면 :

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

@Pravin의 몇 가지 주요 실수. 먼저 'object'를 UIView *로 정의해야합니다. 그렇지 않으면 [object removeFromSuperview]와 함께 컴파일러 오류가 발생합니다. 둘째, for 루프는 이미 iCount를 줄이므로 iCount-- 줄을 사용하여 여분의 것을 건너 뜁니다. 마지막으로 위의 두 가지 작동 및 올바른 접근 방식이 있으며 귀하의 접근 방식은 더 우아하거나 빠르지 않습니다.
amergin

5
각 반복 당신이 할 iCount++iCount--이 경우 무한 루프 수 있도록, 같은 인덱스를 떠나 [oSubView count]>0. 이것은 확실히 버그이며 NOT 및 유효 코드입니다.
Daniel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.