正确的方法是从视图层次结构中删除子视图并销毁它?

40

我有一个包含多个子视图的父UIView。定期需要删除一个子视图并将其从系统中彻底删除。正确的做法是什么?我尝试了这个:

UIView *v = [self.containerView viewWithTag:[n integerValue]];

[v removeFromSuperview];

我做了一些更改,结果很奇怪,之前存在的UIView也消失了。发生了什么?

8个回答

72

试试这个:

UIView *v = [self.containerView viewWithTag:[n integerValue]];
v.hidden = YES;
[self.containerView bringSubviewToFront:v];
[v removeFromSuperview];

从UIView类文档中发现了一件事情,看看最后一句话:

removeFromSuperview 将接收器与其超级视图和窗口断开链接,并将其从响应者链中删除。

  • (void)removeFromSuperview

讨论 如果接收器的超级视图不为nil,则此方法释放接收器。 如果您打算重用视图,请在调用此方法之前保留它,并在使用完毕或将其添加到另一个视图层次结构后适当释放它。

决不要在显示时调用此方法。

更新:现在是2014年,删除而不隐藏子视图完全正常。原始帖子的代码应该按原样工作:

UIView *v = [self.containerView viewWithTag:[n integerValue]];
[v removeFromSuperview];
这将移除v及其作为子视图附加到它的任何视图,仅留下containerView和v的任何同级视图。

1
不要在显示时调用此方法,否则会出现不祥的情况。 - Irwin
再简单不过了,就像Blackberry所说的那样 *for (UIView s in [view subviews]) [s removeFromSuperview]; - Fattie
回到2009年,如果在隐藏子视图之前删除它,你会得到一些奇怪的结果。至少我当时看到了这种情况,原帖作者也是如此。UIView类参考文档中曾经有过这样的警告,但现在已被另一个警告所取代。我认为原帖作者删除子视图的方法现在可能是正确的,不需要任何额外的代码。(他只是删除了一个子视图) - mahboudz

40

要从视图中删除所有子视图:

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

如果你只想移除特定的视图,则可以:

for(UIView *subview in [view subviews]) {
  if([subview isKindOfClass:[UIButton class]]) {
     [subview removeFromSuperview];
 } else {
     // Do nothing - not a UIButton or subclass instance
 }
}

您还可以通过标签值删除子视图:

for(UIView *subview in [view subviews]) {
    if(subview.tag==/*your subview tag value here*/) {
        [subview removeFromSuperview];

    } else {
        // Do nothing - not a UIButton or subclass instance
    }
}

3
我喜欢这个答案比被选中的更好。这似乎是一个更直接的方法 - 而且您包括了许多选择,可以删除任何人想要删除的内容。点赞。 - GeneralMike
如果我有多个UIImageView作为按钮的子视图,并且只想删除一个特定的,该怎么办? - 最白目
为每个ImageView添加标签并检查标签值。 - iKushal
Mike,如果这只是一个无关紧要的打字错误...为什么不点击“删除”并删除这里的两个混淆评论呢? - Fattie
正如GeneralMike所说,被接受的答案很奇怪。它不过是for (UIView *s in [view subviews]) [s removeFromSuperview];的简单语句罢了。 - Fattie
显示剩余4条评论

2

Swift 3.0:

let viewToRemove = mySuperView.viewWithTag(myTag)
viewToRemove?.removeFromSuperview()

0

Swift 4:扩展UIView

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

或者

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

0
    override func viewWillAppear(_ animated: Bool)
    {
        super.viewWillAppear(animated)

        if let topController = UIApplication.topViewController() {

            if topController.isKind(of: ProviderHome.self)
            {
                let arrOfSuview = self.view.subviews

                if arrOfSuview.count > 1
                {
                    print("Davender Arr of subviews : \(arrOfSuview)")

                    for i in 0..<arrOfSuview.count
                    {
                        let objSub = arrOfSuview[i]

                        if objSub.tag == 101
                        {
                          objSub.removeFromSuperview()
                        }

                    }



                }


                NotificationCenter.default.addObserver(self, selector: #selector(ProviderHome.handelPushNotification), name: NSNotification.Name(rawValue: "handelPush"), object: nil)

                NotificationCenter.default.addObserver(self, selector: #selector(ProviderHome.handelLocalNotification), name: NSNotification.Name(rawValue: "handelLocal"), object: nil)
            }
        }


    }

@objc func handelPushNotification(_ notification: NSNotification)  {


        let arrOfSuview = self.view.subviews

        if arrOfSuview.count > 1
        {
            print("Davender Arr of subviews : \(arrOfSuview)")

            for i in 0..<arrOfSuview.count
            {
                let objSub = arrOfSuview[i]

                if objSub.tag == 101
                {
                    objSub.removeFromSuperview()
                }

            }

        }

        if notification.userInfo != nil
        {


            let dict = notification.userInfo as! Dictionary<String, Any>

            let d = dict["data"] as! Dictionary<String, Any>

            let action = d["gcm.notification.label"] as! String

            print("current message id :- ", action)

            self.getNotificationId = action

            if getNotificationId != ""
            {
               //call the api for getting Data

                AppDelegate.sharedInstance().myCurrentnotificationId = getNotificationId

                //working code
                let storyboard = UIStoryboard(name: "Provider", bundle: nil)
                let vc = storyboard.instantiateViewController(withIdentifier: "CommonPopUpsVC") as! CommonPopUpsVC
                vc.modalPresentationStyle = .overFullScreen
                vc.view.frame = self.view.frame
                vc.view.tag = 101
                self.view.addSubview(vc.view)
                self.present(vc, animated: true, completion: nil)

            }


       }
    }

0

这是正确的一般想法。那些消失的其他UIView,它们与此UIView的关系是什么?它们是此视图的子视图吗?它们在您删除的视图的dealloc方法中被释放了吗?

您确定您的标签是唯一的吗?

Sujal


我正在尝试移除的视图的所有兄弟视图立即从屏幕上消失了。什么情况? - dugla
所有的兄弟视图都有唯一的标签,这是我引用它们的方式。 - dugla

0
它们只是从显示器上消失了,还是从显示器和视图层次结构中消失了?调试器显示了什么?

0

cell.contentView是否可能与您想要删除的子视图具有相同的标记?根据文档,viewWithTag将会移除:

在接收器层次结构中匹配标记的视图。接收器包括在搜索中。

如果是这种情况,则您可能会无意中从单元格中删除cell.contentView。如果n为零且您的单元格内容视图未设置任何标记,则默认为0并导致发生这种情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接