要点:
我继承了
GMSSyncTileLayer
并覆盖
tileForX:y:zoom:
但无论我泛多少,它都只会叫一次。
为什么?
DETAIL
我们已经实现了自己的TileServer,它位于安全的Web服务之后,因此我们需要传递一个登录令牌来获取磁贴。
该调用是异步POST,对于Web服务调用来说很安静。
因为我必须在NSURLSession标头中传递登录令牌,所以我不能将GET URL传递给
GMSTileURLConstructor urls = http://<tileserver>/gettile?x=3&y=4&zoom=5
所以我继承了GMSSyncTileLayer
@interface SNSyncTileLayer : GMSSyncTileLayer
改写
- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom {
当tileForX:y:Zoom:在第一次调用webservice来调用tile UIImage时调用。
UIImage在委托上返回,并存储在NSDictionary中,其密钥格式为TILE_x_y_Zoom。
对WS的调用是asynch所以 - (UIImage *)tileForX:y:Zoom:第一次调用该tile时总是返回nil。
我注意到的是tileForX:y:Zoom:无论我来回多少都不会再被调用。
例如,在目前的缩放比例中,我横扫整个欧洲。
我看到tileForX:y:缩放:被调用一次,而ws调用是疯狂的,图像存储在我的字典中。
但如果我继续以相同的缩放平移,我会回到欧洲和tileForX:y:缩放:不再被调用。
修复一个 - 下载新磁贴时清除缓存
我尝试在SNSyncTileLayer上创建一个委托,并且每次下载一个新的tile时都会调用它:
[self.snSyncTileLayer clearTileCache];
但是这会擦除所有瓷砖并重新加载它们,因此当你平移时会发生可怕的闪烁。
接下来我唯一的想法是测量地图的平移程度以及超过一半的宽度或高度,然后调用clearTileCache。
这是一个很大的问题,为什么不是tileForX:y:缩放:每次调用?
我被覆盖的课程
//
// SNSyncTileLayer.m
//
#import "SNSyncTileLayer.h"
#import "SNAppDelegate.h"
#import "GoogleTileRequest.h"
#import "SNGoogleTileRequest.h"
#import "GoogleTileImageResult.h"
@interface SNSyncTileLayer()<SNSeaNetWebServicesManagerDelegate>{
BOOL _debugOn;
}
@property (nonatomic, retain) NSMutableDictionary * tileImageCacheDict;
@end
@implementation SNSyncTileLayer
- (instancetype)init
{
self = [super init];
if (self) {
_tileImageCacheDict = [NSMutableDictionary dictionary];
_debugOn = TRUE;
}
return self;
}
- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom {
if(_debugOn)ImportantLog(@"tileForX:(%lu) y:(%lu) zoom:(%lu)", (unsigned long)x,(unsigned long)y,(unsigned long)zoom);
UIImage *tileImage_ = nil;
//tileImage_ = [UIImage imageNamed:@"EmptyTile1.png"];
NSString * keyForTile_ = [NSString stringWithFormat:@"TILE_%lu_%lu_%lu", (unsigned long)x,(unsigned long)y,(unsigned long)zoom];
id dictObj_ = [self.tileImageCacheDict objectForKey:keyForTile_];
if (dictObj_) {
if([dictObj_ isMemberOfClass:[NSNull class]])
{
if(_debugOn)DebugLog(@"tile has been called before but image not downloaded yet:[%@]",keyForTile_);
}
else if([dictObj_ isMemberOfClass:[UIImage class]])
{
if(_debugOn)DebugLog(@"cached image found in dict_ return it:[%@]",keyForTile_);
tileImage_ = (UIImage *)dictObj_;
}
else{
ErrorLog(@"ITEM IN self.tileImageCacheDict not NSNull or UIImage:[%@]", dictObj_);
}
}else{
if(_debugOn)ImportantLog(@"tileForX: CACHED IMAGE NOT FOUND: DOWNLOAD IT[%@]",keyForTile_);
//-----------------------------------------------------------------------------------
//add in temp object - tyring to check if tileForX:Y:Zoom is called more than once
[self.tileImageCacheDict setObject:[NSNull null] forKey:keyForTile_];
//-----------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------
SNAppDelegate *appDelegate = (SNAppDelegate *)[[UIApplication sharedApplication] delegate];
GoogleTileRequest * googleTileRequest_ = [[GoogleTileRequest alloc]init];
googleTileRequest_.X = [NSNumber numberWithInteger:x];
googleTileRequest_.Y = [NSNumber numberWithInteger:y];
googleTileRequest_.Zoom = [NSNumber numberWithInteger:zoom];
#pragma mark TODO - NOW - thur11dec - load from settings
googleTileRequest_.MapType = @"Dark";
//for general errors
appDelegate.snSeaNetWebServicesManager.delegate = self;
//Request should know what class to return too
googleTileRequest_.delegateForRequest = self;
[appDelegate.snSeaNetWebServicesManager ITileController_GoogleTile:googleTileRequest_];
//-----------------------------------------------------------------------------------
return kGMSTileLayerNoTile;
//-----------------------------------------------------------------------------------
}
return tileImage_;
}
#pragma mark -
#pragma mark SNSeaNetWebServicesManagerDelegate
#pragma mark -
-(void) snSeaNetWebServicesManager:(SNSeaNetWebServicesManager *)SNSeaNetWebServicesManager
wsReponseReceivedForRequest:(SNWebServiceRequest *)snWebServiceRequest_
error:(NSError *)error
{
#pragma mark TODO - NOW - thur11dec2014
if(error){
ErrorLog(@"error:%@",error);
}else{
if(snWebServiceRequest_){
if([snWebServiceRequest_ isMemberOfClass:[SNGoogleTileRequest class]])
{
//Result is JSONModel ivar in Request
if(snWebServiceRequest_.resultObject){
GoogleTileImageResult * googleTileImageResult_= (GoogleTileImageResult *)snWebServiceRequest_.resultObject;
UIImage * responseImage_ = googleTileImageResult_.responseImage;
if(responseImage_){
//-----------------------------------------------------------------------------------
//build the key from the parameters
if(snWebServiceRequest_.bodyJsonModel){
NSDictionary *paramsDict = [snWebServiceRequest_.bodyJsonModel toDictionary];
if(paramsDict){
NSString *keyX_ = [paramsDict objectForKey:@"X"];
NSString *keyY_ = [paramsDict objectForKey:@"Y"];
NSString *keyZoom_ = [paramsDict objectForKey:@"Zoom"];
if(keyX_){
if(keyY_){
if(keyZoom_){
NSString * keyForTile_ = [NSString stringWithFormat:@"TILE_%@_%@_%@", keyX_,keyY_,keyZoom_];
if(_debugOn)ImportantLog(@"TILE DOWNLOADED ADD TO CACHE[%@]",keyForTile_);
[self.tileImageCacheDict setObject:responseImage_ forKey:keyForTile_];
//if(_debugOn)DebugLog(@"[[self.tileImageCacheDict allKeys]count]:%lu", (unsigned long)[[self.tileImageCacheDict allKeys]count]);
//-----------------------------------------------------------------------------------
//I ADDED THIS SO delegate could clearTileCache but causes flashing as ALL tiles get reloaded visible ones and ones downloaded but not on map
if(self.delegate){
if([self.delegate respondsToSelector:@selector(snSyncTileLayer:tileDownloadedForX:Y:Zoom:)]){
[self.delegate snSyncTileLayer:self
tileDownloadedForX:keyX_
Y:keyY_
Zoom:keyZoom_
];
}else {
ErrorLog(@"<%@ %@:(%d)> %s delegate[%@] doesnt implement snSyncTileLayer:tileDownloadedForX:Y:Zoom:", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, __PRETTY_FUNCTION__ ,self.delegate);
}
}else{
ErrorLog(@"<%@ %@:(%d)> %s self.delegate is nil", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, __PRETTY_FUNCTION__);
}
//-----------------------------------------------------------------------------------
}else{
ErrorLog(@"keyZoom_ is nil");
}
}else{
ErrorLog(@"keyY_ is nil");
}
}else{
ErrorLog(@"keyX_ is nil");
}
}else{
ErrorLog(@"paramsDict is nil");
}
}else{
ErrorLog(@"self.downloadingTasksDictionary is nil");
}
//-----------------------------------------------------------------------------------
}else{
ErrorLog(@"responseImage_ is nil");
}
}else{
ErrorLog(@"snWebServiceRequest_.resultJsonModel is nil");
}
}
else {
ErrorLog(@"UNHANDLED snWebServiceRequest_:%@", snWebServiceRequest_.class);
}
}else{
ErrorLog(@"snWebServiceRequest_ is nil");
}
}
}
@end
答案 0 :(得分:3)
我还没有这样做,所以我不确定,但我从阅读文档中猜到,你应该将GMSTileLayer
分为GMSSyncTileLayer
而不是GMSSyncTileLayer
。
kGMSTileLayerNoTile
适用于您可以同步(即立即)返回该位置的磁贴的情况。通过返回nil
,您明确指出“此处没有磁贴”,因此它永远不会再次呼叫您的班级,因为您已经回复说没有在那里。 (顺便说一下,您的说明说明您正在返回kGMSTileLayerNoTile
,这表示出现了暂时性错误,但您的代码实际上正在返回GMSTileLayer
)。
GMSTileLayer
类专为您正在使用的异步方法而设计。如果您继承requestTileForX:y:zoom:receiver:
,则GMSTileReceiver
方法应启动后台进程以获取磁贴。当磁贴请求成功时,它会被传递给该方法中提供的{{1}}(您应该保留该接收者的副本以及您的请求)。