ลบบทสัมภาษณ์ทั้งหมดหรือไม่


316

เมื่อแอพของฉันกลับไปที่ตัวควบคุมมุมมองรูทในviewDidAppear:วิธีที่ฉันต้องการลบการดูทั้งหมด

ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


569

แก้ไข:ด้วยความขอบคุณcocoafan : สถานการณ์นี้ยุ่งเหยิงกับความจริงที่ว่าNSViewและUIViewจัดการกับสิ่งต่าง ๆ สำหรับNSView( สำหรับการพัฒนาบนเดสก์ท็อป Mac เท่านั้น) คุณสามารถใช้สิ่งต่อไปนี้:

[someNSView setSubviews:[NSArray array]];

สำหรับUIView(การพัฒนา iOS เท่านั้น) คุณสามารถใช้งานได้อย่างปลอดภัยmakeObjectsPerformSelector:เนื่องจากsubviewsคุณสมบัติจะส่งคืนสำเนาของอาร์เรย์ของการดูย่อย:

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

ขอบคุณTommy ที่ชี้ให้เห็นว่าmakeObjectsPerformSelector:ดูเหมือนจะแก้ไขsubviewsอาเรย์ในขณะที่มันกำลังถูกแจกแจง (ซึ่งมันทำเพื่อNSViewแต่ไม่ใช่สำหรับUIView)

โปรดดูคำถาม SO นี้สำหรับรายละเอียดเพิ่มเติม

หมายเหตุ:การใช้วิธีใดวิธีหนึ่งจากสองวิธีนี้จะลบทุกมุมมองที่มุมมองหลักของคุณมีและปล่อยมุมมองนั้นหากไม่ได้เก็บไว้ที่อื่น จากเอกสารของ Apple ในremoveFromSuperview :

หาก superview ของผู้รับไม่เป็นศูนย์วิธีนี้จะปล่อยผู้รับ หากคุณวางแผนที่จะนำมุมมองนั้นกลับมาใช้ใหม่ให้แน่ใจว่าได้เก็บมุมมองนั้นไว้ก่อนที่จะเรียกวิธีการนี้และให้แน่ใจว่าได้ปล่อยมุมมองนั้นตามความเหมาะสมเมื่อคุณทำเสร็จแล้ว


9
คุณแน่ใจว่าปลอดภัยหรือไม่ มันจะทำการเปลี่ยนแปลงรายการในขณะที่วนซ้ำและฉันไม่สามารถหาคำสั่งที่ชัดเจนในเอกสารของ Apple
Tommy

8
@ ทอมมี่: นั่นเป็นประเด็นที่ดี Googling บางคำตอบUIViewกลับมา: ส่งคืนสำเนาของsubviewsอาร์เรย์ที่ไม่แน่นอนดังนั้นรหัสนี้ใช้งานได้ เรื่องราวที่แตกต่างอย่างสิ้นเชิงบนเดสก์ท็อปโดยที่รหัสเดียวกันจะมีข้อยกเว้น ดูstackoverflow.com/questions/4665179/…
e.James

3
UIView ไม่ตอบสนองต่อ setSubviews: ใช่หรือไม่
cocoafan

4
วิธี Xamarin: someUIView.Subviews.All (p => p.RemoveFromSuperview);
เบอนัวต์ Jadinon

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
@ คะแนนมันชัดเจนกว่าและชัดเจนกว่าในแบบที่เขาทำได้ ละเอียดและอ่านง่าย> ประหยัดการกดแป้น
taylorcressy

33
@aylorcressy คุณควรพูดว่า "การอ่านได้สำคัญกว่าการบันทึกการกดแป้น" แทน "การอ่าน> การบันทึกการกดแป้น" และจากนั้นความคิดเห็นของคุณจะอ่านง่ายขึ้น :-)
arlomedia

1
อย่าลืมว่าถ้า [self.view subviews] ทำการคำนวณใด ๆ ภายใต้ประทุนการวางลงในลูปโดยตรงอาจทำให้การคำนวณเหล่านั้นซ้ำแล้วซ้ำอีก ประกาศก่อนที่ลูปจะทำให้แน่ใจว่าพวกเขาจะดำเนินการเพียงครั้งเดียว
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
ยินดีต้อนรับสู่ Stack Overflow! คุณจะพิจารณาเพิ่มคำบรรยายเพื่ออธิบายว่าทำไมรหัสนี้จึงใช้งานได้และอะไรทำให้เป็นคำตอบของคำถาม สิ่งนี้จะเป็นประโยชน์กับผู้ที่ถามคำถามและใครก็ตามที่เข้ามา นอกจากนี้คำตอบที่ได้รับการยอมรับแล้วรวมถึงรหัสที่เป็นหลักเช่นนี้
Andrew Barber

5
สิ่งนี้จะช่วยได้อย่างไรมากกว่าคำตอบที่ยอมรับได้: มันเหมือนกัน ทำไมต้องเขียนสิ่งนี้
Rambatino

8

สิ่งนี้ใช้ได้กับ OSX เท่านั้นเนื่องจากใน iOS จะมีการเก็บสำเนาของอาร์เรย์ไว้

เมื่อลบการดูย่อยทั้งหมดคุณควรเริ่มลบตอนท้ายของอาร์เรย์และทำการลบจนกว่าจะถึงจุดเริ่มต้น สามารถทำได้ด้วยรหัสสองบรรทัดนี้:

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();
}

หรือ (มีประสิทธิภาพน้อยกว่า แต่อ่านได้มากกว่า)

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

บันทึก

คุณไม่ควรลบการดูย่อยตามลำดับปกติเนื่องจากอาจทำให้เกิดความผิดพลาดหากมีการลบอินสแตนซ์ UIView ก่อนที่removeFromSuperviewข้อความจะถูกส่งไปยังวัตถุทั้งหมดของอาร์เรย์ (เห็นได้ชัดว่าการลบองค์ประกอบสุดท้ายจะไม่ทำให้เกิดความผิดพลาด)

ดังนั้นรหัส

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

ไม่ควรใช้

อ้างจากเอกสารของ Apple เกี่ยวกับ makeObjectsPerformSelector :

ส่งไปยังแต่ละวัตถุในอาร์เรย์ข้อความที่ระบุโดยตัวเลือกที่กำหนดเริ่มต้นด้วยวัตถุแรกและดำเนินการต่อผ่านอาร์เรย์ไปยังวัตถุสุดท้าย

(ซึ่งจะเป็นทิศทางที่ผิดสำหรับวัตถุประสงค์นี้)


คุณช่วยยกตัวอย่างสิ่งที่คุณอ้างถึงได้ไหม ไม่ทราบว่าคุณหมายถึงอะไรเป็น "องค์ประกอบ" และองค์ประกอบนี้จะถูกลบออกก่อนที่จะเรียก removeFromSuperView อย่างไร
นาย

แต่จะลบอินสแตนซ์ของ UIView ในขณะที่เรียกใช้วิธีนี้ได้อย่างไร คุณหมายถึงถูกลบออกจากอาร์เรย์มุมมองย่อยหรือไม่?
สาธุคุณ

เมื่อremoveFromSuperviewเสร็จสิ้นแล้ว UIView จะถูกลบออกจากอาร์เรย์และถ้าไม่มีอินสแตนซ์อื่น ๆ ที่มีความสัมพันธ์กับ UIView อย่างแน่นหนา UIView ก็จะถูกลบเช่นกัน นี่อาจทำให้เกิดข้อยกเว้นนอกขอบเขต
Daniel

1
Gotcha! ขอบคุณ. ฉันคิดว่าคุณได้รับสำเนาของอาร์เรย์การชมย่อยบน IOS ไม่ว่าในกรณีใดคุณควรทำสำเนาด้วยตัวคุณเองหากคุณต้องการลบการสัมภาษณ์ออก
สาธุคุณ

@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ส่วนขยายSwift :

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

2

ในวัตถุประสงค์ -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 ที่ใช้ autolayout ฉันต้องเพิ่มโค้ดเล็กน้อยเพื่อลบข้อ จำกัด ด้วย

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 ซึ่งกำลังถูกล้างข้อมูล



-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 for loop ของคุณกำลังลดลง iCount อยู่แล้วดังนั้นคุณจึงข้ามอีกหนึ่งบรรทัดด้วย iCount-- ของคุณ และในที่สุดก็มีสองวิธีการทำงานและวิธีการที่ถูกต้องด้านบนและคุณก็ไม่ได้สวยงามและเร็วขึ้น
amergin

5
แต่ละซ้ำที่คุณทำiCount++และออกจากดัชนีเดียวกันดังนั้นมันจะเป็นห่วงอนันต์ถ้าiCount-- [oSubView count]>0นี่เป็นรหัสรถและใช้ไม่ได้แน่นอน
Daniel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.