Ios NSDictionary<;FBGraphUser>*用户语法解释
在Facebook iOS SDK中,将使用以下处理程序返回请求:Ios NSDictionary<;FBGraphUser>*用户语法解释,ios,objective-c,facebook-sdk-3.0,Ios,Objective C,Facebook Sdk 3.0,在Facebook iOS SDK中,将使用以下处理程序返回请求: ^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) { } 此语法与作为公共属性声明的语法id object语法有些相似,只是NSDictionary明确地是id对象,并且该字典符合协议?但是dot语法从何而来,如何声明任意NSFoundation对象与协议相对应,而
^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error) { }
此语法与作为公共属性声明的语法id object
语法有些相似,只是NSDictionary明确地是id对象,并且该字典符合协议?但是dot语法从何而来,如何声明任意NSFoundation对象与协议相对应,而不将对象本身子类化并使其一致
我做了一些额外的研究,似乎不可能在字典中添加一个类别就在字典中使用点符号。但是,我在中没有看到任何语法参考,以表明NSDictionary的这个特定实例符合该符号
Facebook的文档中很少有关于这种包装的工作原理:
FBGraphUser协议代表最常用的属性
Facebook用户对象的。它可用于访问NSD字典
已用FBGraphObject外观包装的对象
如果按照这条线索找到FBGraphObject文档,那么有一些方法返回符合此“facade…”的词典,但没有进一步解释如何包装词典
所以我想我的问题是:
NSDictionary
,同时它符合FBGraphUser
协议
但是点语法是从哪里来的呢
我不明白。它来自于编写有问题代码的程序员。这是可能的,因为FBGraphUser
协议声明了一些属性,然后可以通过点表示法访问这些属性
如何声明任意NSFoundation对象与协议相对应,而不将对象本身子类化并使其符合
这不是所谓的“NS粉底”,只是基础。它不是不“符合”协议的对象,而是它的类。你自己也展示了它的语法
它是如何实施的?简单:一个类别
#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;
}
#导入
@协议Foo
@属性(只读,赋值)int-answer;
@结束
@接口字典(MyCategory)
@结束
@实现NSDictionary(MyCategory)
-(int)答案
{
返回42;
}
@结束
int main()
{
NSDictionary*d=[NSDictionary dictionary];
NSLog(@“%d”,d.答案);
返回0;
}
这是一个SSCCE,i。E它按原样编译和运行,试试看
要使这种语法正常工作,底层代码是什么样子的
上面回答
它为什么存在
因为语言是这样定义的
facebook为什么要以这种方式实现它,而不是仅仅制作一个他们可以将数据转换成的对象
我不知道,问问Facebook的家伙。基本上,
NSDictionary*user
,意味着一个对象继承自NSDictionary
,添加了FBGraphUser
协议声明的功能(特别是键入访问)
这种方法背后的原因在中有相当详细的描述(FBGraphUser
协议扩展了FBGraphObject
协议)。可能让您感到困惑的是,FBGraphObject
是一个协议(已描述)和一个类(已描述),它继承自NSMutableDictionary
就内部实现而言,这是一些非常高级的Objective-C动态魔法,您可能不想担心。您需要知道的是,如果愿意,您可以将该对象视为字典,或者使用协议中的其他方法。如果您确实想了解详细信息,可以查看以下方法,尤其是:
#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;
}
}
jbat100我可以在Facebook SDK范围之外的其他方式中使用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;
}
}