IBOutletCollection在Interface Builder中设置sorting

我正在使用IBOutletCollections将几个类似的UI元素的实例分组。 尤其是我将许多UIButtons(类似于问答游戏中的蜂鸣器)和一组UILabels(显示分数)分组。 我想确保直接在button上的标签更新分数。 我认为按索引访问它们是最容易的。 不幸的是,即使我以相同的顺序添加它们,它们并不总是具有相同的索引。 在Interface Builder中有没有办法设置正确的顺序。

编辑:几个评论者声称,Xcode的更新版本以连接的顺序返回IBOutletCollections 。 其他人则声称,这种方法在故事板中并不适用于他们。 我没有自己testing过,但是如果你愿意依靠没有logging的行为,那么你可能会发现我在下面提出的显式sorting不再是必要的。


不幸的是,似乎没有办法控制IB中IBOutletCollection的顺序,所以你需要根据视图的某些属性对数组进行sorting。 您可以根据tag属性对视图进行sorting,但在IB中手动设置标签可能相当乏味。

幸运的是,我们倾向于按照我们想要访问的顺序布置视图,所以通常按照x或y的位置对数组进行sorting就足够了:

 - (void)viewDidLoad { [super viewDidLoad]; // Order the labels based on their y position self.labelsArray = [self.labelsArray sortedArrayUsingComparator:^NSComparisonResult(UILabel *label1, UILabel *label2) { CGFloat label1Top = CGRectGetMinY(label1.frame); CGFloat label2Top = CGRectGetMinY(label2.frame); return [@(label1Top) compare:@(label2Top)]; }]; } 

我用cduhn的答案跑了这个NSArray类。 如果现在xcode确实保留了devise时的顺序,那么这个代码并不是真的需要,但是如果你发现自己不得不在IB中创build/重新创build大集合,并且不想担心这可能会帮助(在运行时)。 还有一点需要注意:最有可能的顺序是将对象添加到集合中,这与“身份检查器”选项卡中的“对象ID”有关,当您编辑界面并将新对象引入收集在稍后的时间。

。H

 @interface NSArray (sortBy) - (NSArray*) sortByObjectTag; - (NSArray*) sortByUIViewOriginX; - (NSArray*) sortByUIViewOriginY; @end 

.M

 @implementation NSArray (sortBy) - (NSArray*) sortByObjectTag { return [self sortedArrayUsingComparator:^NSComparisonResult(id objA, id objB){ return( ([objA tag] < [objB tag]) ? NSOrderedAscending : ([objA tag] > [objB tag]) ? NSOrderedDescending : NSOrderedSame); }]; } - (NSArray*) sortByUIViewOriginX { return [self sortedArrayUsingComparator:^NSComparisonResult(id objA, id objB){ return( ([objA frame].origin.x < [objB frame].origin.x) ? NSOrderedAscending : ([objA frame].origin.x > [objB frame].origin.x) ? NSOrderedDescending : NSOrderedSame); }]; } - (NSArray*) sortByUIViewOriginY { return [self sortedArrayUsingComparator:^NSComparisonResult(id objA, id objB){ return( ([objA frame].origin.y < [objB frame].origin.y) ? NSOrderedAscending : ([objA frame].origin.y > [objB frame].origin.y) ? NSOrderedDescending : NSOrderedSame); }]; } @end 

然后按照您select的名称包含头文件,代码可以是:

 - (void)viewDidLoad { [super viewDidLoad]; // Order the labels based on their y position self.labelsArray = [self.labelsArray sortByUIViewOriginY]; } 

不知道什么时候这个改变了,但至less在Xcode 4.2中,这不再是一个问题。 IBOutletCollections现在保留在Interface Builder中添加视图的顺序。

更新:

我做了一个testing项目来validation是这样的情况: IBOutletCollectionTest

我发现Xcode使用连接的ID按字母顺序sorting集合。 如果你打开你的nib文件的版本编辑器,你可以很容易地编辑id(确保它们是唯一的,否则Xcode会崩溃)。

 <outletCollection property="characterKeys" destination="QFa-Hp-9dk" id="aaa-0g-pwu"/> <outletCollection property="characterKeys" destination="ahU-9i-wYh" id="aab-EL-hVT"/> <outletCollection property="characterKeys" destination="Kkl-0x-mFt" id="aac-0c-Ot1"/> <outletCollection property="characterKeys" destination="Neo-PS-Fel" id="aad-bK-O6z"/> <outletCollection property="characterKeys" destination="AYG-dm-klF" id="aae-Qq-bam"/> <outletCollection property="characterKeys" destination="Blz-fZ-cMU" id="aaf-lU-g7V"/> <outletCollection property="characterKeys" destination="JCi-Hs-8Cx" id="aag-zq-6hK"/> <outletCollection property="characterKeys" destination="DzW-qz-gFo" id="aah-yJ-wbx"/> 

这有助于您在IB的Document Outline中手动sorting对象,以便它们在xml代码中顺序显示。

据我所知,并不如此。

作为一种解决方法,您可以按顺序为每个人分配一个标签。 使button的范围为100,101,102等,以及标签200,201,202等。然后将100添加到button的标签以获得其对应标签的标签。 你可以通过使用viewForTag:获取标签viewForTag:

或者,您可以将相应的对象分组到自己的UIView ,因此每个视图只有一个button和一个标签。

看起来IBOutletCollection是如何定制的非常随意的。 也许我不是很了解Nick Lockwood的方法 – 但是我也做了一个新项目,添加了一堆UILabel,并将它们按照添加到视图的顺序连接到一个集合。

logging之后,我得到了一个随机的订单。 这是非常令人沮丧的。

我的解决方法是在IB中设置标签,然后像这样sorting集合:

 [self setResultRow1:[self sortCollection: [self resultRow1]]]; 

这里,resultRow1是一个大约7个标签的IBOutletCollection,通过IB设置标签。 这里是sorting方法:

 -(NSArray *)sortCollection:(NSArray *)toSort { NSArray *sortedArray; sortedArray = [toSort sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { NSNumber *tag1 = [NSNumber numberWithInt:[(UILabel*)a tag]]; NSNumber *tag2 = [NSNumber numberWithInt:[(UILabel*)b tag]]; return [tag1 compare:tag2]; }]; return sortedArray; } 

这样做,我现在可以通过使用[resultRow1 objectAtIndex: i]或类似的东西来访问对象。 这节省了每次需要访问元素时迭代和比较标记的开销。

我需要这个订购UITextField对象的集合来设置键盘上的“下一步”button将导致(字段选项卡)的位置。 这将是一个国际应用程序,所以我想语言的方向是模糊的。

。H

 #import <Foundation/Foundation.h> @interface NSArray (UIViewSort) - (NSArray *)sortByUIViewOrigin; @end 

.M

 #import "NSArray+UIViewSort.h" @implementation NSArray (UIViewSort) - (NSArray *)sortByUIViewOrigin { NSLocaleLanguageDirection horizontalDirection = [NSLocale characterDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]]; NSLocaleLanguageDirection verticalDirection = [NSLocale lineDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]]; UIView *window = [[UIApplication sharedApplication] delegate].window; return [self sortedArrayUsingComparator:^NSComparisonResult(id object1, id object2) { CGPoint viewOrigin1 = [(UIView *)object1 convertPoint:((UIView *)object1).frame.origin toView:window]; CGPoint viewOrigin2 = [(UIView *)object2 convertPoint:((UIView *)object2).frame.origin toView:window]; if (viewOrigin1.y < viewOrigin2.y) { return (verticalDirection == kCFLocaleLanguageDirectionLeftToRight) ? NSOrderedDescending : NSOrderedAscending; } else if (viewOrigin1.y > viewOrigin2.y) { return (verticalDirection == kCFLocaleLanguageDirectionLeftToRight) ? NSOrderedAscending : NSOrderedDescending; } else if (viewOrigin1.x < viewOrigin2.x) { return (horizontalDirection == kCFLocaleLanguageDirectionTopToBottom) ? NSOrderedDescending : NSOrderedAscending; } else if (viewOrigin1.x > viewOrigin2.x) { return (horizontalDirection == kCFLocaleLanguageDirectionTopToBottom) ? NSOrderedAscending : NSOrderedDescending; } else return NSOrderedSame; }]; } @end 

用法(布局后)

 - (void)viewDidAppear:(BOOL)animated { _availableTextFields = [_availableTextFields sortByUIViewOrigin]; UITextField *previousField; for (UITextField *field in _availableTextFields) { if (previousField) { previousField.nextTextField = field; } previousField = field; } } 

这是我在Array<UIView>上创build的一个扩展,通过tag进行sorting,例如,在工作时使用IBOutletCollection

 extension Array where Element: UIView { /** Sorts an array of `UIView`s or subclasses by `tag`. For example, this is useful when working with `IBOutletCollection`s, whose order of elements can be changed when manipulating the view objects in Interface Builder. Just tag your views in Interface Builder and then call this method on your `IBOutletCollection`s in `viewDidLoad()`. - author: Scott Gardner - seealso: * [Source on GitHub](http://bit.ly/SortUIViewsInPlaceByTag) */ mutating func sortUIViewsInPlaceByTag() { sortInPlace { (left: Element, right: Element) in left.tag < right.tag } } }