IOS में एक uiviewcontroller में सभी साक्षात्कारों को कैसे सूचीबद्ध करें?


86

मैं एक में सभी साक्षात्कारों को सूचीबद्ध करना चाहता हूं UIViewController। मैंने कोशिश की self.view.subviews, लेकिन सभी उप-सूचियों को सूचीबद्ध नहीं किया गया है, उदाहरण के लिए, साक्षात्कार में UITableViewCellनहीं मिले हैं। कोई उपाय?


आप पुनरावर्ती खोज द्वारा सभी साक्षात्कारों का पता लगा सकते हैं। यानी चेक सबव्यू के साक्षात्कार हैं ..
महेश

जवाबों:


171

आपको उप-विचारों को पुनरावृत्ति करना होगा।

- (void)listSubviewsOfView:(UIView *)view {

    // Get the subviews of the view
    NSArray *subviews = [view subviews];

    // Return if there are no subviews
    if ([subviews count] == 0) return; // COUNT CHECK LINE

    for (UIView *subview in subviews) {

        // Do what you want to do with the subview
        NSLog(@"%@", subview);

        // List the subviews of subview
        [self listSubviewsOfView:subview];
    }
}

जैसा कि @Greg Meletic द्वारा टिप्पणी की गई है, आप ऊपर दिए गए COUNT CHECK LINE को छोड़ सकते हैं।


20
तकनीकी तौर पर, आपको यह जांचने की आवश्यकता नहीं है कि सबव्यू काउंट 0. है
ग्रेग मैलेटिक

5
NSLog (@ "\ n% @", [(id) self.view performSelector: @selector (recursiveDescription)]); यह रेखा आपके जैसे ही परिणाम प्रिंट करती है!
हेमांग

यदि आप यहां हैं, तो कृपया recursiveDescription@natbro से अधिक सरल उत्तर की जांच करें - stackoverflow.com/a/8962824/429521
फेलिप सबिनो

यहाँ @EmptyStack समाधान में मेरा सुधार है। यह वर्ग के नाम और फ्रेम को पुन: निर्देशित इंडेंट का समन्वय दिखाता है
पियरे डी लेस्पिन

35

दृश्य पदानुक्रम को डंप करने के लिए निर्मित xcode / gdb का तरीका उपयोगी है - प्रतिदेयता, प्रतिलेखन, http://developer.apple.com/library/ios/#technotes/tn2239/_index.html

यह अधिक संपूर्ण दृश्य पदानुक्रम को आउटपुट करता है जो आपको उपयोगी लग सकता है:

> po [_myToolbar recursiveDescription]

<UIToolbarButton: 0xd866040; frame = (152 0; 15 44); opaque = NO; layer = <CALayer: 0xd864230>>
   | <UISwappableImageView: 0xd8660f0; frame = (0 0; 0 0); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0xd86a160>>

[_myToolbar recursiveDescription]मेरे कोड में या कहीं और कवि को कहां रखा जाए ।
पवन

1
@WildPointer वह कंसोल के बारे में बात कर रहा है। ऐसा करने के लिए आपको कहीं न कहीं एक ब्रेकप्वाइंट की जरूरत होती है। पीओ = प्रिंट ऑब्जेक्ट
स्माइलबॉट

1
+1 Apple इस दृष्टिकोण की सिफारिश करता है (कोको और कोको टच सत्र में डब्ल्यूडब्ल्यूडीसी 2013 के छिपे हुए रत्न के अनुसार, टिप # 5)।
स्लिप डी। थॉम्पसन

@ पवन यहां मेरा जवाब देखिए । मैंने इस उत्तर का पुनर्लेखन किया।
शहद

16

स्विफ्ट में सुरुचिपूर्ण पुनरावर्ती समाधान:

extension UIView {

    func subviewsRecursive() -> [UIView] {
        return subviews + subviews.flatMap { $0.subviewsRecursive() }
    }

}

आप किसी भी UIView पर उप-साक्षात्कार () कॉल कर सकते हैं:

let allSubviews = self.view.subviewsRecursive()

13

आपको पुनरावर्ती प्रिंट करने की आवश्यकता है, यह विधि भी दृश्य की गहराई के आधार पर टैब करती है

-(void) printAllChildrenOfView:(UIView*) node depth:(int) d
{
    //Tabs are just for formatting
    NSString *tabs = @"";
    for (int i = 0; i < d; i++)
    {
        tabs = [tabs stringByAppendingFormat:@"\t"];
    }

    NSLog(@"%@%@", tabs, node);

    d++; //Increment the depth
    for (UIView *child in node.subviews)
    {
        [self printAllChildrenOfView:child depth:d];
    }

}

13

यहाँ स्विफ्ट संस्करण है

 func listSubviewsOfView(view:UIView){

    // Get the subviews of the view
    var subviews = view.subviews

    // Return if there are no subviews
    if subviews.count == 0 {
        return
    }

    for subview : AnyObject in subviews{

        // Do what you want to do with the subview
        println(subview)

        // List the subviews of subview
        listSubviewsOfView(subview as UIView)
    }
}

7

मैं पार्टी के लिए थोड़ा लेट हूँ, लेकिन थोड़ा और सामान्य समाधान:

@implementation UIView (childViews)

- (NSArray*) allSubviews {
    __block NSArray* allSubviews = [NSArray arrayWithObject:self];

    [self.subviews enumerateObjectsUsingBlock:^( UIView* view, NSUInteger idx, BOOL*stop) {
        allSubviews = [allSubviews arrayByAddingObjectsFromArray:[view allSubviews]];
                   }];
        return allSubviews;
    }

@end

6

यदि आप चाहते हैं कि यह एक सरणी है UIView, तो यह एक लाइनर समाधान है ( स्विफ्ट 4+ ):

extension UIView {
  var allSubviews: [UIView] {
    return self.subviews.reduce([UIView]()) { $0 + [$1] + $1.allSubviews }
  }
}

इस समाधान के लिए धन्यवाद! मैंने घंटों बिताए लेकिन फिर भी आपकी पोस्ट ने मुझे बचा लिया!
user2525211

5

मैं इस तरह से उपयोग करता हूं:

NSLog(@"%@", [self.view subviews]);

UIViewController में।


4

विवरण

  • Xcode 9.0.1, स्विफ्ट 4
  • Xcode 10.2 (10E125), स्विफ्ट 5

समाधान

extension UIView {
    private func subviews(parentView: UIView, level: Int = 0, printSubviews: Bool = false) -> [UIView] {
        var result = [UIView]()
        if level == 0 && printSubviews {
            result.append(parentView)
            print("\(parentView.viewInfo)")
        }

        for subview in parentView.subviews {
            if printSubviews { print("\(String(repeating: "-", count: level))\(subview.viewInfo)") }
            result.append(subview)
            if subview.subviews.isEmpty { continue }
            result += subviews(parentView: subview, level: level+1, printSubviews: printSubviews)
        }
        return result
    }
    private var viewInfo: String { return "\(classForCoder), frame: \(frame))" }
    var allSubviews: [UIView] { return subviews(parentView: self) }
    func printSubviews() { _ = subviews(parentView: self, printSubviews: true) }
}

प्रयोग

 view.printSubviews()
 print("\(view.allSubviews.count)")

परिणाम

यहाँ छवि विवरण दर्ज करें


3

मेरे तरीके से, यूआईवीवाई की श्रेणी या विस्तार दूसरों की तुलना में बहुत बेहतर है और पुनरावर्ती सभी साक्षात्कार प्राप्त करने के लिए महत्वपूर्ण बिंदु है

और अधिक जानें:

https://github.com/ZhipingYang/XYDebugView

यहाँ छवि विवरण दर्ज करें

उद्देश्य सी

@implementation UIView (Recurrence)

- (NSArray<UIView *> *)recurrenceAllSubviews
{
    NSMutableArray <UIView *> *all = @[].mutableCopy;
    void (^getSubViewsBlock)(UIView *current) = ^(UIView *current){
        [all addObject:current];
        for (UIView *sub in current.subviews) {
            [all addObjectsFromArray:[sub recurrenceAllSubviews]];
        }
    };
    getSubViewsBlock(self);
    return [NSArray arrayWithArray:all];
}
@end

उदाहरण

NSArray *views = [viewController.view recurrenceAllSubviews];

स्विफ्ट 3.1

extension UIView {
    func recurrenceAllSubviews() -> [UIView] {
        var all = [UIView]()
        func getSubview(view: UIView) {
            all.append(view)
            guard view.subviews.count>0 else { return }
            view.subviews.forEach{ getSubview(view: $0) }
        }
        getSubview(view: self)
        return all
    }
}

उदाहरण

let views = viewController.view.recurrenceAllSubviews()

सीधे, सभी उप-साक्षात्कार प्राप्त करने के लिए अनुक्रम फ़ंक्शन का उपयोग करें

let viewSequence = sequence(state: [viewController.view]) { (state: inout [UIView] ) -> [UIView]? in
    guard state.count > 0 else { return nil }
    defer {
        state = state.map{ $0.subviews }.flatMap{ $0 }
    }
    return state
}
let views = viewSequence.flatMap{ $0 }

2

UITableViewCell में सब-प्रिंट नहीं होने का कारण यह है कि आपको शीर्ष स्तर के सभी साक्षात्कारों को आउटपुट करना होगा। सेल के साक्षात्कार आपके विचार के सीधे उप-साक्षात्कार नहीं हैं।

UITableViewCell के उप-साक्षात्कार प्राप्त करने के लिए, आपको यह निर्धारित करने की आवश्यकता है कि कौन से सब-वे UITableViewell के हैं (उपयोग करके isKindOfClass: आपके प्रिंट लूप में ) और फिर यह सबव्यू के माध्यम से लूप हैं।

संपादित करें: आसान UIView डिबगिंग पर यह ब्लॉग पोस्ट संभावित रूप से मदद कर सकता है


2

मैंने एक व्यू कंट्रोलर द्वारा रखे गए सभी विचारों को सूचीबद्ध करने के लिए एक श्रेणी लिखी है जो पहले पोस्ट किए गए उत्तरों से प्रेरित है।

@interface UIView (ListSubviewHierarchy)
- (NSString *)listOfSubviews;
@end

@implementation UIView (ListSubviewHierarchy)
- (NSInteger)depth
{
    NSInteger depth = 0;
    if ([self superview]) {
        deepth = [[self superview] depth] + 1;
    }
    return depth;
}

- (NSString *)listOfSubviews
{
    NSString * indent = @"";
    NSInteger depth = [self depth];

    for (int counter = 0; counter < depth; counter ++) {
        indent = [indent stringByAppendingString:@"  "];
    }

    __block NSString * listOfSubviews = [NSString stringWithFormat:@"\n%@%@", indent, [self description];

    if ([self.subviews count] > 0) {
        [self.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            UIView * subview = obj;
            listOfSubviews = [listOfSubviews stringByAppendingFormat:@"%@", [subview listOfSubviews]];
        }];
    }
    return listOfSubviews;
}
@end

व्यू कंट्रोलर द्वारा रखे गए सभी विचारों को सूचीबद्ध करने के लिए NSLog("%@",[self listOfSubviews]), जिसका selfअर्थ है व्यू कंट्रोलर। हालांकि यह कुशल नहीं है।

इसके अलावा, आप NSLog(@"\n%@", [(id)self.view performSelector:@selector(recursiveDescription)]);एक ही काम करने के लिए उपयोग कर सकते हैं , और मुझे लगता है कि यह मेरे कार्यान्वयन से अधिक कुशल है।


2

सरल स्विफ्ट उदाहरण:

 var arrOfSub = self.view.subviews
 print("Number of Subviews: \(arrOfSub.count)")
 for item in arrOfSub {
    print(item)
 }

1

आप एक फैंसी ऐरे ट्रिक को आजमा सकते हैं, जैसे:

[self.view.subviews makeObjectsPerformSelector: @selector(printAllChildrenOfView)];

कोड की सिर्फ एक पंक्ति। बेशक, आपको अपने printAllChildrenOfViewपैरामीटर को समायोजित करने की आवश्यकता हो सकती है ताकि कोई पैरामीटर न लिया जा सके या एक नई विधि न बनाई जा सके।


1

स्विफ्ट 2.0 संगत

यहाँ एक सामान्य दृष्टिकोण के सभी साक्षात्कार प्राप्त करने के लिए एक पुनरावर्ती विधि है:

extension UIView {
  func subviewsList() -> [UIView] {
      var subviews = self.subviews
      if subviews.count == 0 {
          return subviews + []
      }
      for v in subviews {
         subviews += v.listSubviewsOfView()
      }
      return subviews
  }
}

तो आप इस तरह से हर जगह कॉल कर सकते हैं:

let view = FooController.view
let subviews = view.subviewsList()

1

यहाँ छवि विवरण दर्ज करें

सबसे छोटा उपाय

for subview in self.view.subviews {
    print(subview.dynamicType)
}

परिणाम

UIView
UIView
UISlider
UISwitch
UITextField
_UILayoutGuide
_UILayoutGuide

टिप्पणियाँ

  • जैसा कि आप देख सकते हैं, यह विधि पुनरावर्ती तरीके से उप-सूची को सूचीबद्ध नहीं करती है। उसके लिए कुछ अन्य उत्तर देखें।

1

यह इस उत्तर का पुनर्लेखन है :

आपको सबसे पहले उस ऑब्जेक्ट का पॉइंटर / रेफरेंस प्राप्त करना होगा जिसे आप उसके सभी सबव्यू को प्रिंट करना चाहते हैं। कभी-कभी आपको उस वस्तु को उसके सबव्यू के माध्यम से एक्सेस करना आसान लगता है। की तरह po someSubview.superview। यह आपको कुछ इस तरह देगा:

Optional<UIView>
   some : <FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
  • FaceBookApp आपके ऐप का नाम है
  • WhatsNewView आपके प्रकार हैsuperview
  • 0x7f91747c71f0 पर्यवेक्षक के लिए सूचक है।

सुपर व्यू प्रिंट करने के लिए, आपको ब्रेकपॉइंट्स का उपयोग करना चाहिए।


अब इस चरण को करने के लिए आप 'व्यू डिबग पदानुक्रम' पर क्लिक कर सकते हैं। ब्रेकपाइंट की कोई आवश्यकता नहीं है

यहाँ छवि विवरण दर्ज करें

तब आप आसानी से कर सकते थे:

po [0x7f91747c71f0 recursiveDescription]

जो मेरे लिए कुछ इस तरह लौटा:

<FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
   | <UIStackView: 0x7f91747c75f0; frame = (45 60; 264 93); layer = <CATransformLayer: 0x610000230ec0>>
   |    | <UIImageView: 0x7f916ef38c30; frame = (10.6667 0; 243 58); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x61000003b840>>
   |    | <UIStackView: 0x7f91747c8230; frame = (44.6667 58; 174.667 35); layer = <CATransformLayer: 0x6100006278c0>>
   |    |    | <FacebookApp.CopyableUILabel: 0x7f91747a80b0; baseClass = UILabel; frame = (44 0; 86.6667 16); text = 'What's New'; gestureRecognizers = <NSArray: 0x610000c4a770>; layer = <_UILabelLayer: 0x610000085550>>
   |    |    | <FacebookApp.CopyableUILabel: 0x7f916ef396a0; baseClass = UILabel; frame = (0 21; 174.667 14); text = 'Version 14.0.5c Oct 05, 2...'; gestureRecognizers = <NSArray: 0x610000c498a0>; layer = <_UILabelLayer: 0x610000087300>>
   | <UITextView: 0x7f917015ce00; frame = (45 183; 264 403); text = '   •   new Adding new feature...'; clipsToBounds = YES; gestureRecognizers = <NSArray: 0x6100000538f0>; layer = <CALayer: 0x61000042f000>; contentOffset: {0, 0}; contentSize: {264, 890}>
   |    | <<_UITextContainerView: 0x7f9170a13350; frame = (0 0; 264 890); layer = <_UITextTiledLayer: 0x6080002c0930>> minSize = {0, 0}, maxSize = {1.7976931348623157e+308, 1.7976931348623157e+308}, textContainer = <NSTextContainer: 0x610000117b20 size = (264.000000,340282346638528859811704183484516925440.000000); widthTracksTextView = YES; heightTracksTextView = NO>; exclusionPaths = 0x61000001bc30; lineBreakMode = 0>
   |    |    | <_UITileLayer: 0x60800023f8a0> (layer)
   |    |    | <_UITileLayer: 0x60800023f3c0> (layer)
   |    |    | <_UITileLayer: 0x60800023f360> (layer)
   |    |    | <_UITileLayer: 0x60800023eca0> (layer)
   |    | <UIImageView: 0x7f9170a7d370; frame = (-39 397.667; 36 2.33333); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x60800023f4c0>>
   |    | <UIImageView: 0x7f9170a7d560; frame = (258.667 -39; 2.33333 36); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x60800023f5e0>>
   | <UIView: 0x7f916ef149c0; frame = (0 587; 354 0); layer = <CALayer: 0x6100006392a0>>
   | <UIButton: 0x7f91747a8730; frame = (0 0; 0 0); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x610000639320>>
   |    | <UIButtonLabel: 0x7f916ef00a80; frame = (0 -5.66667; 0 16); text = 'See More Details'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x610000084d80>>

जैसा कि आपने अनुमान लगाया होगा कि मेरे पर्यवेक्षक के 4 साक्षात्कार हैं:

  • एक स्टैक व्यू (स्टैक व्यू में स्वयं एक छवि है और एक अन्य स्टैक व्यू है (इस स्टैक व्यू में 2 कस्टम लेबल हैं))
  • एक टेक्स्ट दृश्य
  • एक दृश्य
  • एक बटन

यह मेरे लिए काफी नया है, लेकिन इससे मुझे अपने विचारों के फ्रेम (और पाठ और प्रकार) को डीबग करने में मदद मिली है। मेरा एक साक्षात्कार स्क्रीन पर दिखाई नहीं दे रहा था, इसलिए पुनरावर्ती लेखन का उपयोग किया और मुझे अपने सबवू में से एक की चौड़ाई का एहसास हुआ 0... इसलिए मैंने इसकी बाधाओं को ठीक किया और सबव्यू दिखाई दे रहा था।


0

वैकल्पिक रूप से यदि आप एक UIView एक्सटेंशन से सभी साक्षात्कारों (और नेस्टेड साक्षात्कार) की एक सरणी वापस करना चाहते हैं:

func getAllSubviewsRecursively() -> [AnyObject] {
    var allSubviews: [AnyObject] = []

    for subview in self.subviews {
        if let subview = subview as? UIView {
            allSubviews.append(subview)
            allSubviews = allSubviews + subview.getAllSubviewsRecursively()
        }
    }

    return allSubviews
}

0

एसी # ज़मारिन संस्करण:

void ListSubviewsOfView(UIView view)
{
    var subviews = view.Subviews;
    if (subviews.Length == 0) return;

    foreach (var subView in subviews)
    {
        Console.WriteLine("Subview of type {0}", subView.GetType());
        ListSubviewsOfView(subView);
    }
}

वैकल्पिक रूप से, यदि आप किसी विशिष्ट प्रकार के सभी उपखंडों को खोजना चाहते हैं जिसका मैं उपयोग करता हूं:

List<T> FindViews<T>(UIView view)
{
    List<T> allSubviews = new List<T>();
    var subviews = view.Subviews.Where(x =>  x.GetType() == typeof(T)).ToList();

    if (subviews.Count == 0) return allSubviews;

       foreach (var subView in subviews)
       {
            allSubviews.AddRange(FindViews<T>(subView));
        }

    return allSubviews;

}

0

मैंने इसे UIViewकेवल अच्छे पेड़ के प्रारूप के साथ मुद्रित करने के लिए अनुक्रमणिका को पारित करने वाले फ़ंक्शन को कॉल करने की श्रेणी में किया है । यह जेम्स वेबस्टर द्वारा पोस्ट किए गए उत्तर का एक और विकल्प है ।

#pragma mark - Views Tree

- (void)printSubviewsTreeWithIndex:(NSInteger)index
{
    if (!self)
    {
        return;
    }


    NSString *tabSpace = @"";

    @autoreleasepool
    {
        for (NSInteger x = 0; x < index; x++)
        {
            tabSpace = [tabSpace stringByAppendingString:@"\t"];
        }
    }

    NSLog(@"%@%@", tabSpace, self);

    if (!self.subviews)
    {
        return;
    }

    @autoreleasepool
    {
        for (UIView *subView in self.subviews)
        {
            [subView printViewsTreeWithIndex:index++];
        }
    }
}

मुझे उम्मीद है यह मदद करेगा :)


0
- (NSString *)recusiveDescription:(UIView *)view
{
    NSString *s = @"";
    NSArray *subviews = [view subviews];
    if ([subviews count] == 0) return @"no subviews";

    for (UIView *subView in subviews) {
         s = [NSString stringWithFormat:@"<%@; frame = (%f %f : %f %f) \n ",NSStringFromClass([subView class]), subView.frame.origin.x, subView.frame.origin.y ,subView.frame.size.width, subView.frame.size.height];  
        [self recusiveDescription:subView];
    }
    return s;
}

-1

self.view.subviews विचारों के उत्तराधिकार को बनाए रखता है। यदि आप नीचे दिए गए कुछ करने के लिए uitableviewcell के साक्षात्कार प्राप्त करते हैं।

 for (UIView *subView in self.view.subviews) {
      if ([subView isKindOfClass:[UITableView class]]) {
            for (UIView *tableSubview in subView.subviews) {
                .......
            }
      }
 }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.