จะลบมุมมองย่อยทั้งหมดใน Swift ได้อย่างไร


176

ฉันกำลังมองหาวิธีง่าย ๆ ในการลบการดูย่อยทั้งหมดทันทีจากผู้กำกับดูแลแทนที่จะลบทีละรายการ

//I'm trying something like this, but is not working
let theSubviews : Array = container_view.subviews
for (view : NSView) in theSubviews {
    view.removeFromSuperview(container_view)
}

ฉันกำลังคิดถึงอะไร

UPDATE

container_viewแอปของฉันมีหลัก ฉันต้องเพิ่มมุมมองอื่น ๆ เป็นมุมมองย่อยcontainer_viewเพื่อให้การนำทางเรียงลำดับ

ดังนั้นเมื่อคลิกปุ่มเพื่อ "เปิด" หน้าใดหน้าหนึ่งฉันจำเป็นต้องลบการดูทั้งหมดและเพิ่มหน้าใหม่

อัปเดต 2 - โซลูชันที่ใช้งานได้ (OS X)

ฉันเดาว่า Apple คงซ่อมแล้ว

ตอนนี้มันง่ายกว่าที่เคยเพียงแค่โทร:

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

2
ฉันต้องการจะชี้ให้เห็นว่า @ sulthan คำตอบในขณะที่ฝังด้วยผ้าขี้ริ้วคือคำตอบที่ดีกว่า: stackoverflow.com/questions/24312760/…
Christopher Swasey

@ChristopherSwasey Swift 4 ให้ข้อผิดพลาด: ไม่สามารถกำหนดให้กับคุณสมบัติ: 'subviews' เป็นคุณสมบัติแบบ get-only :(
William T. Mallard

2
@ WilliamT.Mall ต้องทำซ้ำหลายครั้งว่าวิธีการและคำถามนี้เกี่ยวกับ MacOS ไม่ใช่ iOS?
Fogmeister

คำตอบ:


358

แก้ไข: (ขอบคุณ Jeremiah / Rollo)

วิธีที่ดีที่สุดในการทำสิ่งนี้ใน Swift สำหรับ iOS คือ:

view.subviews.forEach({ $0.removeFromSuperview() }) // this gets things done
view.subviews.map({ $0.removeFromSuperview() }) // this returns modified array

^^ คุณสมบัติเหล่านี้สนุก!

let funTimes = ["Awesome","Crazy","WTF"]
extension String { 
    func readIt() {
        print(self)
    }
}

funTimes.forEach({ $0.readIt() })

//// สิ้นสุดการแก้ไข

แค่ทำสิ่งนี้:

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

หรือหากคุณกำลังมองหาชั้นเรียนที่เฉพาะเจาะจง

for view:CustomViewClass! in self.view.subviews {
        if view.isKindOfClass(CustomViewClass) {
            view.doClassThing()
        }
    }

ใน Xcode 7.0 beta 6 สิ่งนี้จะสร้างคำเตือน: "ไม่ได้ใช้ผลการโทรไปที่" แผนที่ " ฉันหวังว่าสิ่งนี้จะได้รับการแก้ไขในเวอร์ชั่นสุดท้าย
Ferschae Naej

ฉันสังเกตเห็นเช่นกัน! ฉันจะอัปเดตโพสต์เมื่อ Xcode ออกมาจากเบต้าและปัญหายังคงมีอยู่
Bseaborn

8
คำเตือน, result of call to 'map' is unused ไม่ใช่ข้อผิดพลาด Array.mapในภาษาส่วนใหญ่จะส่งกลับอาร์เรย์ที่ปรับเปลี่ยน view.subviews.forEachวิธีที่เทียบเท่าซึ่งไม่กลับอาร์เรย์จะเป็น
Rollo

for view:CustomViewClass! in self.view.subviews where view.isKindOfClass(CustomViewClass) { view.doClassThing() }
iTSangar

ฉันจะยืนยันว่านี่คือ "โดยวิธีที่ดีที่สุดในการทำสิ่งนี้ใน Swift" ดูstackoverflow.com/a/24314054/1974224
Cristik

41

สำหรับ iOS / Swift เพื่อกำจัดการดูทั้งหมดที่ฉันใช้:

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

เพื่อกำจัด subviews ทั้งหมดของคลาสเฉพาะ (เช่น UILabel) ฉันใช้:

for v in view.subviews{
   if v is UILabel{
      v.removeFromSuperview()
   }
}

31

รหัสสามารถเขียนได้ง่ายขึ้นดังต่อไปนี้

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

18

นี่ควรเป็นทางออกที่ง่ายที่สุด

let container_view: NSView = ...
container_view.subviews = []

(ดูลบการสัมภาษณ์ทั้งหมดหรือไม่สำหรับวิธีอื่น)


โปรดทราบว่านี่เป็นคำถามMacOSและคำตอบนี้ใช้ได้กับMacOSเท่านั้น มันไม่ทำงานบน iOS


นี่เป็นวิธีที่ง่ายที่สุดแน่นอน ... removeFromSuperview จะถูกเรียกโดยอัตโนมัติสำหรับแต่ละมุมมองที่ไม่อยู่ในอาร์เรย์ย่อยของการดูอีกต่อไป
Christopher Swasey

2
@Dayayeah พวกเขาไม่ได้ แต่มีความแตกต่างใหญ่ระหว่างNSView(OS X) และUIView(iOS)
Sulthan

@Sulthan คุณพูดถูก ฉันมาที่นี่เพื่อรับคำตอบอย่างรวดเร็วสำหรับ UIView และไม่ได้อ่านข้อมูลโค้ดทั้งหมดของคุณ)
datayeah

1
Swift 4 ให้ข้อผิดพลาด: ไม่สามารถกำหนดให้กับคุณสมบัติ: 'subviews' เป็นคุณสมบัติแบบ get-only :(
William T. Mallard

1
@AmrAngry อีกครั้งฉันทำซ้ำนี้ก็มักจะเป็นคำถามที่ Mac OS สำหรับNSViewไม่ iOS UIViewและ มีเพียงคนที่ไม่สนใจที่จะอ่านคำถามและแท็กดังนั้นมันจึงเต็มไปด้วยคำตอบของ iOS
Sulthan

10

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

ในการแก้ไขปัญหานี้ฉันได้:

let subViews: Array = self.subviews.copy()
for (var subview: NSView!) in subViews
{
    subview.removeFromSuperview()
}

โดยทำ. คัดลอก () ฉันสามารถทำการลบแต่ละมุมมองย่อยในขณะที่กลายพันธุ์อาร์เรย์ self.subviews นี่เป็นเพราะอาร์เรย์ที่คัดลอก (มุมมองย่อย) มีการอ้างอิงทั้งหมดไปยังวัตถุและไม่ได้กลายพันธุ์

แก้ไข: ในกรณีของคุณฉันคิดว่าคุณจะใช้:

let theSubviews: Array = container_view.subviews.copy()
for (var view: NSView!) in theSubviews
{
    view.removeFromSuperview()
}

ทำงานได้ดี! ขอบคุณ
Alberto Bellini

สวัสดีลองทำสิ่งต่อไปนี้แม้ว่าอาจมีวิธีที่สวยงามกว่านี้มากในการทำเช่นนี้: let subViewsArray: Array = (parentView.subviews as NSArray).copy() as Array<NSView>
Adam Richards


9

ส่วนขยายสำหรับลบการชมทั้งหมดจะถูกลบออกอย่างรวดเร็ว

import Foundation
import UIKit

extension UIView {
    /// Remove allSubView in view
    func removeAllSubViews() {
        self.subviews.forEach({ $0.removeFromSuperview() })
    }

}

1
แผนที่ทำไม ต่างประเทศอาจจะ? subviews.forEach {$ 0.removeFromSuperview ()}
Zaporozhchenko Oleksandr

1
ใช่คุณถูก @Aleksandr ฉันคิดว่าเมื่อฉันกำลังเขียนนี้ฉันไม่ได้ใช้กาแฟของฉัน
YannSteph

6

ลองสิ่งนี้:

var subViews = parentView.subviews as Array<UIView>

      for someView in subViews
      {
          someView.removeFromSuperview()
      }

อัปเดต : หากคุณรู้สึกอยากผจญภัยคุณสามารถเพิ่มส่วนขยายบน UIView ได้ดังแสดงด้านล่าง:

extension UIView
{
    func removeAllSubViews()
    {
       for subView :AnyObject in self.subviews
       {
            subView.removeFromSuperview()
       }
    }

}

และเรียกมันว่าสิ่งนี้:

parentView.removeAllSubViews()

2 สิ่งเล็ก ๆ น้อย ๆ : ฉันกำลังทำงานกับ osx ดังนั้นมันจะ <NSView> ใช่ไหม จากนั้นฉันได้รับ "ข้อผิดพลาดร้ายแรง: ดัชนีอาร์เรย์อยู่นอกช่วง": /
Alberto Bellini

ใช่ฉันคิดว่า OSX เป็น NSView คุณได้รับข้อผิดพลาดร้ายแรงที่ไหน
azamsharp

คุณแน่ใจหรือว่ามุมมองพาเรนต์ของคุณมีองค์ประกอบย่อย
azamsharp

ใช่! ถ้าฉันทำ println (parentView.subviews) ฉันจะได้รับ 1
Alberto Bellini

มันแปลกมาก! มักจะอยู่นอกช่วงหมายความว่าคุณกำลังเข้าถึงดัชนีซึ่งไม่มีอยู่จริงและโดยปกติฉันเชื่อว่ามันเกิดจากการใช้ for for loop กับดัชนีอย่าง i ++
azamsharp

5

ใน xcodebeta6 สิ่งนี้ได้ผล

    var subViews = self.parentView.subviews
    for subview in subViews as [UIView]   {
        subview.removeFromSuperview()
    }

นั่นคือ iOS ฉันต้องการวิธีแก้ปัญหาสำหรับ OS X
Alberto Bellini

ทางออกที่ดีสำหรับ IOS +1
inVINCEable

3

ฉันเขียนส่วนขยายนี้:

extension UIView {
    func lf_removeAllSubviews() {
        for view in self.subviews {
            view.removeFromSuperview()
        }
    }
}

เพื่อให้คุณสามารถใช้ self.view.lf_removeAllSubviews ใน UIViewController ฉันจะใส่มันในhttps://github.com/superarts/LFrameworkเวอร์ชัน swift ของฉันในภายหลังเมื่อฉันมีประสบการณ์มากขึ้นใน swift (ประสบการณ์ 1 วันจนถึงตอนนี้และใช่สำหรับ API ที่ฉันเลิกใช้ขีดเส้นใต้)


3

สวิฟท์ 3

หากคุณเพิ่มแท็กในมุมมองของคุณคุณสามารถลบมุมมองที่เฉพาะเจาะจง

for v in (view?.subviews)!
{
    if v.tag == 321
    {
         v.removeFromSuperview()
    }
 }

ทำไมไม่view.subviews.filter({$0.tag != 321}).forEach({$0.removeFromSuperview()})?
AlexanderZ

3

สวิฟท์ 5

ฉันสร้างวิธีการต่าง ๆ 2 วิธีเพื่อลบมุมมองย่อย และใช้งานง่ายกว่าถ้าเราใส่เข้าไปextension

extension UIView {
    /// Remove all subview
    func removeAllSubviews() {
        subviews.forEach { $0.removeFromSuperview() }
    }

    /// Remove all subview with specific type
    func removeAllSubviews<T: UIView>(type: T.Type) {
        subviews
            .filter { $0.isMember(of: type) }
            .forEach { $0.removeFromSuperview() }
    }
}

2

ไวยากรณ์ของคุณปิดอยู่เล็กน้อย ตรวจสอบให้แน่ใจว่าคุณส่งอย่างชัดเจน

 let theSubviews : Array<NSView> = container_view.subviews as Array<NSView>
 for view in theSubviews {
     view.removeFromSuperview()
 }

@ David ใช่ฉันจะพยายามทำให้มันใกล้เคียงกับรหัสเริ่มต้นของ FoxNos มากที่สุด
แจ็ค

2

คุณต้องลองสิ่งนี้

func clearAllScrollSubView ()
{
    let theSubviews = itemsScrollView.subviews

    for (var view) in theSubviews
    {

        if view is UIView
        {
            view.removeFromSuperview()
        }

    }
}

นั่นคือ UI ไม่ใช่ NS ที่นี่เรากำลังพูดถึง OS X หากใช้งานได้ดีโดยแทนที่ UI ด้วย NS คุณไม่ดีใช่มั้ย :)
อัลแบร์โตเบลลินี

1

สำหรับการลบเพียงแค่พรีวิวย่อยของคลาสเฉพาะ - นี่เป็นรหัส Swift เดียวที่ทำงานกับฉันใน Xcode6.1.1 สมมติว่าคุณต้องการลบเฉพาะพรีวิวย่อยประเภทUIButton ...

for subView in nameofmysuperview.subviews {
    if subView.isKindOfClass(UIButton) {
        subView.removeFromSuperview()
    }
}

1

หนึ่งในสายการบิน:

while(view.subviews.count > 0) {(view.subviews[0] as NSView).removeFromSuperview()}

ผมคิดว่าวิธีการนี้สามารถอ่านได้มากกว่า "หนึ่งสมุทร" โดยใช้แผนที่หรือforEach foreachและแผนที่สั้น ๆนั้นเข้าใจยากเนื่องจากตรรกะมีความเป็นนามธรรมมากกว่า


1

สำหรับ Swift 3

ฉันทำดังต่อไปนี้เพราะเพียงแค่ลบออกจาก superview ไม่ได้ลบปุ่มออกจากอาร์เรย์

    for k in 0..<buttons.count {

      buttons[k].removeFromSuperview()

    }


    buttons.removeAll()

1

ลองสิ่งนี้ฉันทดสอบสิ่งนี้:

  let theSubviews = container_view.subviews
  for subview in theSubviews {
      subview.removeFromSuperview()
  }

1

สำหรับ Swift 4.+

extension UIView {
     public func removeAllSubViews() {
          self.subviews.forEach({ $0.removeFromSuperview() })

}

ฉันหวังว่านี่จะใช้งานอย่างเต็มรูปแบบสำหรับคุณ


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