描述乐高游戏版块最好的方式是展示其使用方法。让我们通过spotify网络API查询一些艺术家。以下是从此端点的一个示例响应。
{
"artists" : {
"href" : "https://api.spotify.com/v1/search?query=tania+bowra&offset=0&limit=20&type=artist",
"items" : [ {
"external_urls" : {
"spotify" : "https://open.spotify.com/artist/08td7MxkoHQkXnWAYD8d6Q"
},
"followers" : {
"href" : null,
"total" : 12
},
"genres" : [ ],
"href" : "https://api.spotify.com/v1/artists/08td7MxkoHQkXnWAYD8d6Q",
"id" : "08td7MxkoHQkXnWAYD8d6Q",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/f2798ddab0c7b76dc2d270b65c4f67ddef7f6718",
"width" : 640
}, {
"height" : 300,
"url" : "https://i.scdn.co/image/b414091165ea0f4172089c2fc67bb35aa37cfc55",
"width" : 300
}, {
"height" : 64,
"url" : "https://i.scdn.co/image/8522fc78be4bf4e83fea8e67bb742e7d3dfe21b4",
"width" : 64
} ],
"name" : "Tania Bowra",
"popularity" : 4,
"type" : "artist",
"uri" : "spotify:artist:08td7MxkoHQkXnWAYD8d6Q"
} ],
"limit" : 20,
"next" : null,
"offset" : 0,
"previous" : null,
"total" : 1
}
}
在我们的示例中,我们真正关心的是位于键路径artists.items
的艺术家对象。我们稍后会使用这个键路径。让我们隔离我们的艺术家对象以进行映射,它看起来像这样
{
"external_urls" : {
"spotify" : "https://open.spotify.com/artist/08td7MxkoHQkXnWAYD8d6Q"
},
"followers" : {
"href" : null,
"total" : 12
},
"genres" : [ ],
"href" : "https://api.spotify.com/v1/artists/08td7MxkoHQkXnWAYD8d6Q",
"id" : "08td7MxkoHQkXnWAYD8d6Q",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/f2798ddab0c7b76dc2d270b65c4f67ddef7f6718",
"width" : 640
}, {
"height" : 300,
"url" : "https://i.scdn.co/image/b414091165ea0f4172089c2fc67bb35aa37cfc55",
"width" : 300
}, {
"height" : 64,
"url" : "https://i.scdn.co/image/8522fc78be4bf4e83fea8e67bb742e7d3dfe21b4",
"width" : 64
} ],
"name" : "Tania Bowra",
"popularity" : 4,
"type" : "artist",
"uri" : "spotify:artist:08td7MxkoHQkXnWAYD8d6Q"
}
让我们看看它作为Objective-C对象是如何建模的。
首先,我们需要创建我们的对象并确保其符合JSONMappableObject
协议。现在我们的对象看起来是这样的。
SpotifyArtist.h
#import <Foundation/Foundation.h>
#import <JSONMapping/JSONMapping.h>
@interface SpotifyArtist : NSObject <JSONMappableObject>
@end
现在让我们填写映射到JSON属性。我们的最终模型头将看起来像这样
SpotifyArtist.h
#import <Foundation/Foundation.h>
#import <JSONMapping/JSONMapping.h>
@interface SpotifyArtist : NSObject <JSONMappableObject>
@property (strong, nonatomic) NSURL *externalSpotifyUrl;
@property (nonatomic) NSInteger numberOfFollowers;
@property (strong, nonatomic) NSArray *genres;
@property (strong, nonatomic) NSURL *url;
@property (copy, nonatomic) NSString *identifier;
@property (strong, nonatomic) NSArray *images;
@property (copy, nonatomic) NSString *name;
@property (nonatomic) NSInteger popularity;
@property (copy, nonatomic) NSString *type;
@property (strong, nonatomic) NSURL *uri;
@end
JSONMappableObject
协议要求实现一个返回NSMutableDictionary
的实例方法,名为mapping
。此方法将在将JSON响应转换为模型对象时在内部使用。建模支持以下语法
mapping[@"<#propertyName#>"] = @"<#associatedJsonKeyPath#>";
此操作试图智能地映射,如果您的属性是一个对应于JSONMappableObject
的类,它将自动进行映射。如果您的属性是JSONMappableObject
的数组,则需要显式声明类型,因为这无法通过反射发现。为此,您可以使用以下语法
mapping[@"<#arrayPropertyName#>@<#ClassName#>"] = @"<#associatedJsonKeyPath#>";
@
语法是JSONMapping的一个重要特性,并且将会经常使用。如果您想有一个更安全的类型,可以使用此便利函数来声明您的键
propertyMap(@"<#propertyName#>", [<#classType#> class])
这种方式映射更安全,这样如果您重构了类名,就不需要执行项目搜索替换键映射。
此语法也可以用来声明一个与其类一起使用的JSONMappableTransformer
。更多关于这个我们稍后再说。让我们看看SpotifyArtist
的映射
SpotifyArtist.m
#import "SpotifyArtist.h"
@implementation SpotifyArtist
- (NSMutableDictionary *)mapping {
NSMutableDictionary *mapping = [NSMutableDictionary dictionary];
// Note keypaths in associated JSON
mapping[@"externalSpotifyUrl"] = @"external_urls.spotify";
mapping[@"numberOfFollowers"] = @"followers.total";
mapping[@"genres"] = @"genres";
mapping[@"url"] = @"href";
mapping[@"identifier"] = @"id";
// Note array type specification
mapping[@"images@SpotifyImageRef"] = @"images";
mapping[@"name"] = @"name";
mapping[@"popularity"] = @"popularity";
mapping[@"type"] = @"type";
mapping[@"uri"] = @"uri";
return mapping;
}
@end
如上所示,我们的images
属性是一个数组,我们正在将其内容映射到我们尚未创建的SpotifyImageRef
模型。让我们看看在images
键中包含的JSON
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/f2798ddab0c7b76dc2d270b65c4f67ddef7f6718",
"width" : 640
}, {
"height" : 300,
"url" : "https://i.scdn.co/image/b414091165ea0f4172089c2fc67bb35aa37cfc55",
"width" : 300
}, {
"height" : 64,
"url" : "https://i.scdn.co/image/8522fc78be4bf4e83fea8e67bb742e7d3dfe21b4",
"width" : 64
} ]
让我们创建一个类似于以下的模型以表示单个对象
SpotifyImageRef.h
#import <Foundation/Foundation.h>
#import <JSONMapping/JSONMapping.h>
@interface SpotifyImageRef : NSObject <JSONMappableObject>
@property (nonatomic) NSInteger height;
@property (nonatomic) NSInteger width;
@property (copy, nonatomic) NSURL *url;
@end
注意:如果您愿意,可以在实现文件中声明 JSONMappableObject 协议。这种方法在示例中更为清晰。
SpotifyImageRef.m
#import "SpotifyImageRef.h"
@implementation SpotifyImageRef
- (NSMutableDictionary *)mapping {
NSMutableDictionary *mapping = [NSMutableDictionary dictionary];
mapping[@"height"] = @"height";
mapping[@"width"] = @"width";
mapping[@"url"] = @"url";
return mapping;
}
@end
这是一个相对直接的对象,我们的属性名称与 JSON 直接对应。目前,在映射中声明这些属性仍然是必要的,这样做的目的是为了允许绝对控制操作。
就是这样,我们的模型已全部设置完成,现在我们需要为 Spotify API 设置端点。
我更喜欢将端点声明在一个文件中,因为它可以防止在添加端点时需要添加额外的导入,并且许多端点最终会相互依赖。
在您的端点文件中,导入
SpotifyEndpoints.h
#import <Foundation/Foundation.h>
#import <PlayDoh/PDEndpoint.h>
我将要做的第一件事是声明一个基本端点。这样做是为了提供基本 URL 和为特定 API 想要的任何其他请求配置。
#import <Foundation/Foundation.h>
#import <PlayDoh/PDEndpoint.h>
@interface SpotifyBaseEndpoint : PDEndpoint
@end
现在让我们来看看实现
SpotifyEndpoints.m
#import "SpotifyEndpoints.h"
#import "SpotifyArtist.h"
@implementation SpotifyBaseEndpoint
- (NSString *)baseUrl {
return @"https://api.spotify.com/v1";
}
@end
Spotify 是一个现代且简洁的 API,大多数特性都能很容易地推断出来。如果您想要对基本端点有更多控制,您可以通过添加更多方法重写来创建更复杂的结构。更具体的 API 可能看起来像这样
@implementation GHBaseEndpoint
- (NSSet *)acceptableContentTypes {
return [NSSet setWithObjects:@"text/html", @"application/json", nil];
}
- (AFHTTPRequestSerializer<AFURLRequestSerialization> *)requestSerializer {
return [AFJSONRequestSerializer serializer];
}
- (NSDictionary *)headerFields {
NSMutableDictionary *headerFields = [NSMutableDictionary dictionary];
headerFields[@"Accept"] = @"application/vnd.github.v3+json";
NSString *token = [storage accessToken];
if (token) {
NSString *tokenHeader = [NSString stringWithFormat:@"Token %@", token];
headerFields[GHNetworkingHeaderKeyAuthorization] = tokenHeader;
}
return headerFields;
}
- (NSString *)baseUrl {
return @"https://api.github.com";
}
@end
好了,现在回到 Spotify。是时候为我们的搜索添加一个新的端点了。这个端点,以及所有未来的希望使用这个基本 URL 的端点,将继承自我们的 Spotify 基端点。
添加了搜索端点后,我们的端点文件看起来是这样的
SpotifyEndpoints.h
#import <Foundation/Foundation.h>
#import <PlayDoh/PDEndpoint.h>
@interface SpotifyBaseEndpoint : PDEndpoint
@end
// Note subclass
@interface SpotifySearchEndpoint : SpotifyBaseEndpoint
@end
SpotifyEndpoints.m
#import "SpotifyEndpoints.h"
#import "SpotifyArtist.h"
@implementation SpotifyBaseEndpoint
- (NSString *)baseUrl {
return @"https://api.spotify.com/v1";
}
@end
@implementation SpotifySearchEndpoint
- (Class)returnClass {
return [SpotifyArtist class];
}
- (NSString *)endpointUrl {
return @"search";
}
- (NSString *)responseKeyPath {
return @"artists.items";
}
@end
用于实现的端点至少需要实现 3 个方法:baseUrl、endpointUrl 和 returnClass。在上面的 SpotifySearchEndpoint 中,您会注意到 baseUrl 没有重写。这是因为它继承了 SpotifyBaseEndpoint,该端点重写了 baseUrl。所有未来的子类都可以继承这个基础。
baseUrl - API 的基本 URL。端点将附加到这个 URL 上。
endpointUrl - 端点的 URL。您可以通过在 slug 前面加冒号 :
来声明一个更高级的端点。这些可以智能地映射到对象以生成端点。(关于 slug 映射的更多内容将在后面介绍)。
responseKeyPath - 正如我们在开头所指定的,这是一个简单的示例,我们不需要所有来自响应的信息。我们只想获取位于键路径 artists.items
的艺术家数组。通过在此端点中声明它,我们告诉它。从 URL 端点 search
获取项目,然后从响应中获取键路径 artists.items
的对象。然后将该响应中的对象映射到类型 SpotifyArtist
。
就是这样,我们现在可以使用搜索 API 了!
一切已设置完成,让我们从服务器获取一些对象!至少,Spotify 搜索端点需要两个参数:query : q
和 type artist
、album
或 track
。在我们的示例中,我们查询艺术家,所以我们将类型设置为该值。现在我们初始化端点并调用 get。
PDEndpoint *ep = [SpotifySearchEndpoint endpointWithParameters:@{@"q" : @"beyonce", @"type" : @"artist"}];
[ep getWithCompletion:^(id object, NSError *error) {
NSArray *artists = (NSArray *)object;
NSLog(@"Got artists: %@ w/ error: %@", artists, error);
}];
由于 Objective-C 允许类型转换的灵活性,我们可以在上面的示例中省略类型转换,并显式替换对象为其类型。
PDEndpoint *ep = [SpotifySearchEndpoint endpointWithParameters:@{@"q" : @"beyonce", @"type" : @"artist"}];
[ep getWithCompletion:^(NSArray *artists, NSError *error) {
NSLog(@"Got artists: %@ w/ error: %@", artists, error);
}];
这也可以用于单个模型对象,而不仅仅是 NSArray
。有关更多信息,请参阅文档中的头部说明!
-- 更多文档即将推出,请参阅头文件
-- 更多文档即将推出,请参阅头文件