在使用Xcode时,是否有任何可以在.nib/.xib中设置和使用的ID,可以在运行时从代码中查询以识别特定视图实例?
特别是在我们的界面中有多个相同的NSView子类副本时,我们如何确定我们当前正在查看哪个副本?
在使用Xcode时,是否有任何可以在.nib/.xib中设置和使用的ID,可以在运行时从代码中查询以识别特定视图实例?
特别是在我们的界面中有多个相同的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];
通用的NSView
对象无法在Interface Builder中设置其tag
属性。在NSView
上,tag
方法是只读方法,只能在NSView
的子类中实现。 NSView
没有实现setTag:
方法。
我怀疑其他答案所提到的是NSControl
的实例,它定义了一个-setTag:
方法,并且有一个Interface Builder字段可以让你设置标签。
对于通用视图,您可以使用用户定义的运行时属性。这使您可以预设视图对象中属性的值。因此,如果您的视图定义了以下属性:
@property (strong) NSNumber* viewID;
然后在Interface Builder中Identity inspector的用户自定义属性部分,您可以添加一个具有键路径viewID
、类型Number
和值123
的属性。
然后,在您的视图的 -awakeFromNib
方法中,您可以访问该属性的值。在上面的示例中,您的视图的 viewID
属性将被预设为 123
。
以下是如何在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"
}
编辑:关联对象“key”(声明为const void *key
)需要是不变的。我正在使用Will Pragnell的一个想法(https://dev59.com/OWQo5IYBdhLWcg3wfPUa#18548365)。
在Stack Overflow上搜索其他制作密钥方案。
这是一种简单的方法,在OSX中获取NSView
标签而无需子类化。
尽管NSView
的标签属性是只读的,但是一些继承自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
)。
NSView
上设置标签,因此在一般情况下无法工作。 - JayNSView
。相反,使用一个允许设置标签的子类。你仍然拥有所有的NSView
参数。我在许多情况下都使用它,效果很好。我的建议解决了OP的问题,所以如果你做了-1,请将其删除。 - Jeff