在Facebook iOS SDK中,使用以下处理程序返回请求:
^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error) { }
然后可以通过这样的调用来访问用户变量......
self.userNameLabel.text = user.name;
self.userProfileImage.profileID = user.id;
这种语法有点类似于语法id <protocolDelegate> object
语法,它是一个公共属性声明,除了NSDictionary是明确的id对象,并且该字典符合协议?但点语法来自何处以及如何声明任意NSFoundation对象与协议相对应而没有对对象本身进行子类化并使其符合?
我对dot notation and NSDictionary进行了一些额外的研究,看来如果不向NSDictionary添加类别,就不可能在字典上使用点表示法。但是,我没有看到&lt;&gt;的任何参考。 Apple Documentation中的语法表示NSDictionary的这个特定实例符合该表示法。
Facebook文档对于这种包装的工作原理有点稀疏:
FBGraphUser协议代表最常用的属性 一个Facebook用户对象。它可能用于访问NSDictionary 已用FBGraphObject外观包装的对象。
如果跟随此导致FBGraphObject文档,那么有些方法返回符合此“facade ...”的字典,但没有进一步解释如何包装字典。
所以我猜我的问题很少:
非常感谢任何解释或见解!
答案 0 :(得分:6)
基本上,NSDictionary<FBGraphUser> *user
表示继承自NSDictionary
的对象,添加FBGraphUser
协议声明的功能(特别是类型化访问)。
FBGraphObject documentation中详细描述了这种方法背后的原因(FBGraphUser
协议扩展了FBGraphObject
协议)。让您感到困惑的是FBGraphObject
是一个协议(描述为here)和一个类(描述为here),它继承自NSMutableDictionary
。
就内部实现而言,它是一些非常先进的Objective-C动态魔法,你可能不想担心。您需要知道的是,如果您愿意,可以将对象视为字典,或者使用协议中的其他方法。如果您真的想知道详细信息,可以查看source code for FBGraphObject,特别是这些方法:
#pragma mark -
#pragma mark NSObject overrides
// make the respondsToSelector method do the right thing for the selectors we handle
- (BOOL)respondsToSelector:(SEL)sel
{
return [super respondsToSelector:sel] ||
([FBGraphObject inferredImplTypeForSelector:sel] != SelectorInferredImplTypeNone);
}
- (BOOL)conformsToProtocol:(Protocol *)protocol {
return [super conformsToProtocol:protocol] ||
([FBGraphObject isProtocolImplementationInferable:protocol
checkFBGraphObjectAdoption:YES]);
}
// returns the signature for the method that we will actually invoke
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
SEL alternateSelector = sel;
// if we should forward, to where?
switch ([FBGraphObject inferredImplTypeForSelector:sel]) {
case SelectorInferredImplTypeGet:
alternateSelector = @selector(objectForKey:);
break;
case SelectorInferredImplTypeSet:
alternateSelector = @selector(setObject:forKey:);
break;
case SelectorInferredImplTypeNone:
default:
break;
}
return [super methodSignatureForSelector:alternateSelector];
}
// forwards otherwise missing selectors that match the FBGraphObject convention
- (void)forwardInvocation:(NSInvocation *)invocation {
// if we should forward, to where?
switch ([FBGraphObject inferredImplTypeForSelector:[invocation selector]]) {
case SelectorInferredImplTypeGet: {
// property getter impl uses the selector name as an argument...
NSString *propertyName = NSStringFromSelector([invocation selector]);
[invocation setArgument:&propertyName atIndex:2];
//... to the replacement method objectForKey:
invocation.selector = @selector(objectForKey:);
[invocation invokeWithTarget:self];
break;
}
case SelectorInferredImplTypeSet: {
// property setter impl uses the selector name as an argument...
NSMutableString *propertyName = [NSMutableString stringWithString:NSStringFromSelector([invocation selector])];
// remove 'set' and trailing ':', and lowercase the new first character
[propertyName deleteCharactersInRange:NSMakeRange(0, 3)]; // "set"
[propertyName deleteCharactersInRange:NSMakeRange(propertyName.length - 1, 1)]; // ":"
NSString *firstChar = [[propertyName substringWithRange:NSMakeRange(0,1)] lowercaseString];
[propertyName replaceCharactersInRange:NSMakeRange(0, 1) withString:firstChar];
// the object argument is already in the right place (2), but we need to set the key argument
[invocation setArgument:&propertyName atIndex:3];
// and replace the missing method with setObject:forKey:
invocation.selector = @selector(setObject:forKey:);
[invocation invokeWithTarget:self];
break;
}
case SelectorInferredImplTypeNone:
default:
[super forwardInvocation:invocation];
return;
}
}
答案 1 :(得分:4)
此语法有点类似于语法id对象语法
“有点类似”?怎么“相同”?
该字典符合协议
Nah,声明说你必须传入一个类为NSDictionary
的对象,同时符合FBGraphUser
协议。
但点语法来自哪里
我不明白这一点。它来自编写这段代码的程序员。这是可能的,因为FBGraphUser
协议声明了一些属性,然后可以通过点表示法访问。
如何说明任意NSFoundation对象对应的协议没有对对象本身进行子类化并使其符合?
它不被称为“NSFoundation”,只是基金会。并且它不是与协议“对应”(因为它相当“符合”)的对象,而是它的类。你只是自己展示了这个语法。
它是如何实现的?简单:一个类别。
#import <Foundation/Foundation.h>
@protocol Foo
@property (readonly, assign) int answer;
@end
@interface NSDictionary (MyCategory) <Foo>
@end
@implementation NSDictionary (MyCategory)
- (int)answer
{
return 42;
}
@end
int main()
{
NSDictionary *d = [NSDictionary dictionary];
NSLog(@"%d", d.answer);
return 0;
}
这是一个SSCCE,我。即它编译并按原样运行,试试吧!
使这种语法工作的底层代码是什么样的?
上面回答。
为什么存在?
因为语言是这样定义的。
为什么facebook会以这种方式实现它,而不是只创建一个可以将数据转换成对象的对象?
我不知道,问问Facebook的人。