मैं एक UIView के सभी साक्षात्कारों के माध्यम से कैसे लूप कर सकता हूं, और उनके साक्षात्कार और उनके साक्षात्कार


82

मैं एक यूआईवीवाई के सभी साक्षात्कारों और उनके साक्षात्कारों और उनके साक्षात्कारों के माध्यम से कैसे लूप कर सकता हूं?


7
यदि आप वास्तव में लूप की आवश्यकता के माध्यम से करते हैं तो स्वीकृत उत्तर सही है, यदि केवल एक दृश्य की तलाश है, तो इसे टैग करें और इसके बजाय व्यूविटैग का उपयोग करें - अपने आप को कुछ दर्द से बचाएं! - developer.apple.com/library/ios/documentation/UIKit/Reference/…
नॉर्मन एच

जवाबों:


122

पुनरावर्तन का उपयोग करें:

// UIView+HierarchyLogging.h
@interface UIView (ViewHierarchyLogging)
- (void)logViewHierarchy;
@end

// UIView+HierarchyLogging.m
@implementation UIView (ViewHierarchyLogging)
- (void)logViewHierarchy
{
    NSLog(@"%@", self);
    for (UIView *subview in self.subviews)
    {
        [subview logViewHierarchy];
    }
}
@end

// In your implementation
[myView logViewHierarchy];

2
क्या LogViewHierarchy में फ़ंक्शन पास करने का कोई तरीका है? इस तरह यह अलग-अलग समय में आपकी आवश्यकताओं के अनुरूप हो सकता है।
डोकांग सेप

2
@dhanghang: ओबज-सी ब्लॉक उस उपयोग के मामले के लिए एक महान फिट हैं। आप विधि के लिए एक ब्लॉक पास करते हैं, ब्लॉक को निष्पादित करते हैं और इसे प्रत्येक विधि कॉल के साथ पदानुक्रम नीचे पारित करते हैं।
ओले बेगमैन 14

अच्छा लगा। मैंने नीचे एक स्निपेट पोस्ट किया है जो इस तकनीक में व्हॉट्सएप इंडेंटेशन जोड़ता है।
जेरेडसिंक्लेयर

34

अच्छी तरह से यहाँ UIView वर्ग के लिए पुनरावृत्ति और एक आवरण (श्रेणी / विस्तार) का उपयोग कर मेरा समाधान है।

// UIView+viewRecursion.h
@interface UIView (viewRecursion)
- (NSMutableArray*) allSubViews;
@end

// UIView+viewRecursion.m
@implementation UIView (viewRecursion)
- (NSMutableArray*)allSubViews
{
   NSMutableArray *arr=[[[NSMutableArray alloc] init] autorelease];
   [arr addObject:self];
   for (UIView *subview in self.subviews)
   {
     [arr addObjectsFromArray:(NSArray*)[subview allSubViews]];
   }
   return arr;
}
@end

उपयोग: अब आपको सभी उप दृश्यों के माध्यम से लूपिंग करना चाहिए और आवश्यकतानुसार उन्हें हेरफेर करना चाहिए।

//disable all text fields
for(UIView *v in [self.view allSubViews])
{
     if([v isKindOfClass:[UITextField class]])
     {
         ((UITextField*)v).enabled=NO;
     }
}

3
ध्यान दें कि allSubViewsफ़ंक्शन में मेमोरी लीक हैं : आपको या तो सरणी बनाना चाहिए [[[NSMutableArray alloc] init] autorelease]या जैसा कि [NSMutableArray array](जो समान है)।
ivanzoid

1
"UIView के लिए एक आवरण" से आपका वास्तव में मतलब है "UIView के लिए एक श्रेणी"।
दिमित्रिस

हां दिमित्रिस, मेरा मतलब था श्रेणी।
रामकृष्ण चुंदुरी


16

स्विफ्ट 3 में एक समाधान जो subviewsबिना किसी दृश्य के सभी को शामिल करता है:

extension UIView {
var allSubViews : [UIView] {

        var array = [self.subviews].flatMap {$0}

        array.forEach { array.append(contentsOf: $0.allSubViews) }

        return array
    }
}

इस पंक्ति में ".flatMap {$ 0}" की क्या आवश्यकता है "var array = [self.subviews] .flatMap {$ 0}"?
राहुल पटेल

@RahulPatel यह nilएक सरणी से तत्वों को निकालता है , सुरक्षा के लिए जब साक्षात्कार में बुलाते हैं allSubViews
इलयमणि


12

बस डिबगर के माध्यम से ऐसा करने का एक दिलचस्प तरीका मिला:

http://idevrecipes.com/2011/02/10/exploring-iphone-view-hierarchies/

इस Apple तकनीक का संदर्भ:

https://developer.apple.com/library/content/technotes/tn2239/_index.html#SIOUUIT

बस सुनिश्चित करें कि आपका डिबगर रुका हुआ है (या तो इसे मैन्युअल रूप से विराम दें) और आप इसके लिए पूछ सकते हैं recursiveDescription


10

यहां वास्तविक दृश्य लूपिंग और ब्रेकिंग कार्यक्षमता के साथ एक उदाहरण है।

स्विफ्ट:

extension UIView {

    func loopViewHierarchy(block: (_ view: UIView, _ stop: inout Bool) -> ()) {
        var stop = false
        block(self, &stop)
        if !stop {
            self.subviews.forEach { $0.loopViewHierarchy(block: block) }
        }
    }

}

कॉल उदाहरण:

mainView.loopViewHierarchy { (view, stop) in
    if view is UIButton {
        /// use the view
        stop = true
    }
}

उलटा लूपिंग:

extension UIView {

    func loopViewHierarchyReversed(block: (_ view: UIView, _ stop: inout Bool) -> ()) {
        for i in stride(from: self.highestViewLevel(view: self), through: 1, by: -1) {
            let stop = self.loopView(view: self, level: i, block: block)
            if stop {
                break
            }
        }
    }

    private func loopView(view: UIView, level: Int, block: (_ view: UIView, _ stop: inout Bool) -> ()) -> Bool {
        if level == 1 {
            var stop = false
            block(view, &stop)
            return stop
        } else if level > 1 {
            for subview in view.subviews.reversed() {
            let stop = self.loopView(view: subview, level: level - 1, block: block)
                if stop {
                    return stop
                }
            }
        }
        return false
    }

    private func highestViewLevel(view: UIView) -> Int {
        var highestLevelForView = 0
        for subview in view.subviews.reversed() {
            let highestLevelForSubview = self.highestViewLevel(view: subview)
            highestLevelForView = max(highestLevelForView, highestLevelForSubview)
        }
        return highestLevelForView + 1
    }
}

कॉल उदाहरण:

mainView.loopViewHierarchyReversed { (view, stop) in
    if view is UIButton {
        /// use the view
        stop = true
    }
}

उद्देश्य सी:

typedef void(^ViewBlock)(UIView* view, BOOL* stop);

@interface UIView (ViewExtensions)
-(void) loopViewHierarchy:(ViewBlock) block;
@end

@implementation UIView (ViewExtensions)
-(void) loopViewHierarchy:(ViewBlock) block {
    BOOL stop = NO;
    if (block) {
        block(self, &stop);
    }
    if (!stop) {
        for (UIView* subview in self.subviews) {
            [subview loopViewHierarchy:block];
        }
    }
}
@end

कॉल उदाहरण:

[mainView loopViewHierarchy:^(UIView* view, BOOL* stop) {
    if ([view isKindOfClass:[UIButton class]]) {
        /// use the view
        *stop = YES;
    }
}];

7

ओले बेगेमैन की मदद से। मैंने इसमें ब्लॉक कॉन्सेप्ट को शामिल करने के लिए कुछ लाइनें जोड़ीं।

उविवि + पदानुक्रम

typedef void (^ViewActionBlock_t)(UIView *);
@interface UIView (UIView_HierarchyLogging)
- (void)logViewHierarchy: (ViewActionBlock_t)viewAction;
@end

उविवि + पदानुक्रम

@implementation UIView (UIView_HierarchyLogging)
- (void)logViewHierarchy: (ViewActionBlock_t)viewAction {
    //view action block - freedom to the caller
    viewAction(self);

    for (UIView *subview in self.subviews) {
        [subview logViewHierarchy:viewAction];
    }
}
@end

अपने ViewController में पदानुक्रम श्रेणी का उपयोग करना। अब आपके पास वह स्वतंत्रता है जो आपको करने की आवश्यकता है।

void (^ViewActionBlock)(UIView *) = ^(UIView *view) {
    if ([view isKindOfClass:[UIButton class]]) {
        NSLog(@"%@", view);
    }
};
[self.view logViewHierarchy: ViewActionBlock];

ऐसा लगता है कि मैंने आपके द्वारा यहां प्रस्तावित एक बहुत ही समान समाधान बनाया है। मैंने आगे बढ़कर इसे गीठुब पर पोस्ट किया, यदि अन्य इसे उपयोगी पाते। यहाँ मेरा जवाब है w / लिंक :) stackoverflow.com/a/10440510/553394
एरिक गोल्डबर्ग

मैं ब्लॉक के भीतर से पुनरावृत्ति को रोकने का तरीका कैसे जोड़ सकता हूं? कहते हैं कि मैं एक विशिष्ट दृश्य का पता लगाने के लिए इसका उपयोग कर रहा हूं, एक बार जब मैंने पाया है कि मैं वहां रुकना चाहूंगा और बाकी दृश्य पदानुक्रम को खोजना जारी नहीं रखूंगा।
माइक प्रिंगल

4

कोई नया फ़ंक्शन बनाने की आवश्यकता नहीं है। एक्सकोड के साथ डिबगिंग करते समय बस इसे करें।

एक व्यू कंट्रोलर में एक ब्रेकपॉइंट सेट करें, और इस ब्रेकपॉइंट पर ऐप पॉज़ करें।

खाली क्षेत्र पर राइट क्लिक करें और Xcode की वॉच विंडो में "Add Expression ..." दबाएं।

इस लाइन को इनपुट करें:

(NSString*)[self->_view recursiveDescription]

यदि मान बहुत लंबा है, तो उसे क्लिक करें और "प्रिंट विवरण ऑफ ..." चुनें। आप कंसोल विंडो में self.view के सभी उप-साक्षात्कार देखेंगे। यदि आप स्वयं का साक्षात्कार नहीं देखना चाहते हैं, तो स्वयं -> _ कुछ और देखें।

किया हुआ! नहीं जीडीबी!


क्या आप बता सकते हैं कि 'खाली क्षेत्र' कहाँ है? मैंने एक बार
एक्सकोड

4

यहाँ एक पुनरावर्ती कोड है: -

 for (UIView *subViews in yourView.subviews) {
    [self removSubviews:subViews];

}   

-(void)removSubviews:(UIView *)subView
{
   if (subView.subviews.count>0) {
     for (UIView *subViews in subView.subviews) {

        [self removSubviews:subViews];
     }
  }
  else
  {
     NSLog(@"%i",subView.subviews.count);
    [subView removeFromSuperview];
  }
}

सहायक समाधान और समय सेवर .. thanx 1 plus for u
दिमागी तकनीक Technolabs

3

वैसे, मैंने इस तरह के काम में मदद करने के लिए एक ओपन सोर्स प्रोजेक्ट बनाया। यह वास्तव में आसान है, और एक पदानुक्रम में सभी विचारों पर कोड निष्पादित करने के लिए उद्देश्य-सी 2.0 ब्लॉकों का उपयोग करता है।

https://github.com/egold/UIViewRecursion

उदाहरण:

-(void)makeAllSubviewsGreen
{
    [self.view runBlockOnAllSubviews:^(UIView *view) {

        view.backgroundColor = [UIColor greenColor];
    }];
}

2

यहाँ ऊपर ओले बेगमैन के उत्तर पर भिन्नता है, जो पदानुक्रम को दर्शाने के लिए इंडेंटेशन जोड़ता है:

// UIView+HierarchyLogging.h
@interface UIView (ViewHierarchyLogging)
- (void)logViewHierarchy:(NSString *)whiteSpaces;
@end

// UIView+HierarchyLogging.m
@implementation UIView (ViewHierarchyLogging)
- (void)logViewHierarchy:(NSString *)whiteSpaces {
    if (whiteSpaces == nil) {
        whiteSpaces = [NSString string];
    }
    NSLog(@"%@%@", whiteSpaces, self);

    NSString *adjustedWhiteSpaces = [whiteSpaces stringByAppendingFormat:@"    "];

    for (UIView *subview in self.subviews) {
        [subview logViewHierarchy:adjustedWhiteSpaces];
    }
}
@end

1

इस उत्तर में पोस्ट किया गया कोड सभी विंडो और सभी विचारों और उनके सभी साक्षात्कारों का पता लगाता है। यह NSLog के लिए पदानुक्रम के एक प्रिंटआउट को डंप करने के लिए उपयोग किया गया था, लेकिन आप इसे पदानुक्रम के किसी भी ट्रैवर्सल के आधार के रूप में उपयोग कर सकते हैं। यह दृश्य ट्री को पार करने के लिए एक पुनरावर्ती C फ़ंक्शन का उपयोग करता है।


0

मैंने एक श्रेणी लिखी कुछ विचारों पर बहस करने के लिए कुछ समय पहले ।

IIRC, पोस्ट किया गया कोड वह है जो काम करता है। यदि नहीं, तो यह आपको सही दिशा में इंगित करेगा। अपने जोखिम पर उपयोग करें, आदि।


0

यह पदानुक्रम स्तर को भी प्रदर्शित करता है

@implementation UIView (ViewHierarchyLogging)
- (void)logViewHierarchy:(int)level
{
    NSLog(@"%d - %@", level, self);
    for (UIView *subview in self.subviews)
    {
        [subview logViewHierarchy:(level+1)];
    }
}
@end

0

काश मुझे यह पृष्ठ पहले मिलता, लेकिन अगर (किसी कारण से) आप इसे गैर-पुनरावर्ती रूप से करना चाहते हैं, तो श्रेणी में नहीं और कोड की अधिक पंक्तियों के साथ


0

मुझे लगता है कि सभी उत्तर पुनरावृत्ति (डिबगर विकल्प को छोड़कर) का उपयोग करते हुए श्रेणियों का उपयोग करते हैं। यदि आपको किसी श्रेणी की आवश्यकता नहीं है, तो आप केवल एक इंस्टेंस विधि का उपयोग कर सकते हैं। उदाहरण के लिए, यदि आपको पदानुक्रम में सभी लेबल की एक सरणी प्राप्त करने की आवश्यकता है, तो आप ऐसा कर सकते हैं।

@interface MyViewController ()
@property (nonatomic, retain) NSMutableArray* labelsArray;
@end

@implementation MyViewController

- (void)recursiveFindLabelsInView:(UIView*)inView
{
    for (UIView *view in inView.subviews)
    {
        if([view isKindOfClass:[UILabel class]])
           [self.labelsArray addObject: view];
        else
           [self recursiveFindLabelsInView:view];
    }
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    self.labelsArray = [[NSMutableArray alloc] init];
    [self recursiveFindLabelsInView:self.view];

    for (UILabel *lbl in self.labelsArray)
    {
        //Do something with labels
    }
}

-1

नीचे दी गई विधि एक या अधिक परिवर्तनशील सरणियों का निर्माण करती है, फिर इनपुट दृश्य के साक्षात्कार के माध्यम से लूप करती है। ऐसा करने पर यह आरंभिक सबव्यू जोड़ता है और फिर उस सबव्यू के किसी भी साक्षात्कार के रूप में प्रश्न करता है। अगर सच है, तो यह फिर से खुद को बुलाता है। ऐसा तब तक होता है जब तक कि पदानुक्रम के सभी विचारों को जोड़ नहीं दिया गया हो।

-(NSArray *)allSubs:(UIView *)view {

    NSMutableArray * ma = [NSMutableArray new];
    for (UIView * sub in view.subviews){
        [ma addObject:sub];
        if (sub.subviews){
            [ma addObjectsFromArray:[self allSubs:sub]];
        }
    }
    return ma;
}

कॉल का उपयोग करें:

NSArray * subviews = [self allSubs:someView];

1
का उपयोग करें संपादित करें कि कैसे इस कोड काम करता है और सिर्फ कोड देना नहीं है, के रूप में एक स्पष्टीकरण मदद भविष्य पाठकों के लिए और अधिक होने की संभावना है समझाने लिंक। इसका जवाब भी देखें । स्रोत
जेड फॉक्स

1
कृपया मेरी टिप्पणी ऊपर देखें।
जेड फॉक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.