是否有任何类型的ID可以通过Xcode在.nib / .xib中使用和设置,可以在运行时查询以从代码中识别特定的视图实例?
特别是在我们的界面中拥有相同NSView子类的多个副本时,我们如何知道我们当前正在查看哪个?
答案 0 :(得分:13)
在Interface Builder中,有一种方法可以设置NSView的“标识符”。在这种情况下,我将使用标识符“54321”作为标识符字符串。
NSView符合NSUserInterfaceItemIdentification Protocol,它是NSString的唯一标识符。您可以遍历视图层次结构并找到具有该标识符的NSView。
因此,要在这篇关于获取NSView列表Get ALL views and subview of NSWindow的帖子的基础上构建,您可以找到具有所需标识符的NSView:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSView *viewToFind = [self viewWithIdentifier:@"54321"];
}
- (NSView *)viewWithIdentifier:(NSString *)identifier
{
NSArray *subviews = [self allSubviewsInView:self.window.contentView];
for (NSView *view in subviews) {
if ([view.identifier isEqualToString:identifier]) {
return view;
}
}
return nil;
}
- (NSMutableArray *)allSubviewsInView:(NSView *)parentView {
NSMutableArray *allSubviews = [[NSMutableArray alloc] initWithObjects: nil];
NSMutableArray *currentSubviews = [[NSMutableArray alloc] initWithObjects: parentView, nil];
NSMutableArray *newSubviews = [[NSMutableArray alloc] initWithObjects: parentView, nil];
while (newSubviews.count) {
[newSubviews removeAllObjects];
for (NSView *view in currentSubviews) {
for (NSView *subview in view.subviews) [newSubviews addObject:subview];
}
[currentSubviews removeAllObjects];
[currentSubviews addObjectsFromArray:newSubviews];
[allSubviews addObjectsFromArray:newSubviews];
}
for (NSView *view in allSubviews) {
NSLog(@"View: %@, tag: %ld, identifier: %@", view, view.tag, view.identifier);
}
return allSubviews;
}
或者,由于您使用的是NSView子类,因此可以在运行时设置每个视图的“标记”。 (或者,您可以在运行时设置标识符。)标记的好处是,有一个预先构建的函数,用于查找具有特定标记的视图。
// set the tag
NSInteger tagValue = 12345;
[self.myButton setTag:tagValue];
// find it
NSButton *myButton = [self.window.contentView viewWithTag:12345];
答案 1 :(得分:10)
通用NSView
对象不能在Interface Builder中设置其tag
属性。 tag
上的NSView
方法是只读方法,只能在NSView
的子类中实现。 NSView
未实施setTag:
方法。
我怀疑其他答案是指NSControl
定义-setTag:
方法的实例,并且有一个Interface Builder字段可以设置标记。
您可以对通用视图执行的操作是使用用户定义的运行时属性。这允许您在视图对象中预设属性的值。因此,如果您的视图定义了这样的属性:
@property (strong) NSNumber* viewID;
然后,在Interface Builder中Identity检查器的用户定义属性部分中,您可以添加一个包含键路径viewID
,类型Number
和值123
的属性。 / p>
在视图的-awakeFromNib
方法中,您可以访问该属性的值。您会发现,在上面的示例中,您视图的viewID
属性已预先设置为123
。
答案 2 :(得分:1)
这里介绍了如何在OSX中模拟“标签”而不进行子类化。
在iOS中:
{
// iOS:
// 1. You add a tag to a view and add it as a subView, as in:
UIView *masterView = ... // the superview
UIView *aView = ... // a subview
aView.tag = 13;
[masterView addSubview:aView];
// 2. Later, to retrieve the tagged view:
UIView *aView = [masterView viewWithTag:13];
// returns nil if there's no subview with that tag
}
等效于OSX:
#import <objc/runtime.h> // for associated objects
{
// OSX:
// 1. Somewhere early, create an invariant memory address
static void const *tag13 = &tag13; // put at the top of the file
// 2. Attach an object to the view to which you'll be adding the subviews:
NSView *masterView = ... // the superview
NSView *aView = ... // a subview
[masterView addSubview:aView];
objc_setAssociatedObject(masterView, tag13, aView, OBJC_ASSOCIATION_ASSIGN);
// 3. Later, to retrieve the "tagged" view:
NSView *aView = objc_getAssociatedObject(masterView, tag13);
// returns nil if there's no subview with that associated object "tag"
}
编辑:关联的对象“键”(声明为const void *key
)必须是不变的。我正在使用Will Pragnell(https://stackoverflow.com/a/18548365/236415)的想法。
在堆栈溢出中搜索其他用于生成密钥的方案。
答案 3 :(得分:-1)
这是一种无需子类即可在OSX中获取NSView
标签的简单方法。
尽管NSView
的tag属性是只读的,但某些对象
从NSView
继承的具有读/写标签属性。
例如,NSControl
和NSImageView
具有读/写标记属性。
因此,只需使用NSControl
而不是NSView
,然后禁用(或忽略)
NSControl
件事情。
- (void)tagDemo
{
NSView *myView1 = [NSView new];
myView1.tag = 1; // Error: "Assignment to readonly property"
// ---------
NSControl *myView2 = [NSControl new]; // inherits from NSView
myView2.tag = 2; // no error
myView2.enabled = NO; // consider
myView2.action = nil; // consider
// ---------
NSImageView *myView3 = [NSImageView new]; // inherits from NSControl
myView3.tag = 3; // no error
myView3.enabled = NO; // consider
myView3.action = nil; // consider
}
稍后,如果您使用viewWithTag:
来获取视图,请确保将NSControl
(或NSImageView
)指定为返回类型。