- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我试图实现的最终状态是拥有一个正在运行的计时器来刷新“车辆”的集合 annotations
. annotation
coordinates
使用计时器每 60 秒成功刷新一次,但用户必须调用 mapView:regionWillChangeAnimated
和 map View :regionWillChangeAnimated
代表们。这些代表正在正确地工作和移动车辆 annotations
, 但我想要 annotations
无需用户与屏幕交互即可自主移动。
这是我的方法:
1) 启动计时器..这非常有效!
//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#pragma mark Timers
//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dispatch_source_t CreateDispatchTimer(uint64_t interval,
uint64_t leeway, dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer)
{
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, interval), interval * NSEC_PER_SEC, (1ull * NSEC_PER_SEC) / 10);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer;
}
- (void)startTimer
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
double secondsToFire = 60.000f;
double secondsLeeway = 2.000f;
_timer = CreateDispatchTimer(secondsToFire, secondsLeeway, queue, ^{
// Do something
//Method Call to Refresh NSMutableArray of Vehicle Models
[self RefreshVehicles];
NSLog(@"TIMER TASK CALLED");
});
}
- (void)cancelTimer
{
if (_timer) {
dispatch_source_cancel(_timer);
_timer = nil;
}
}
计时器用于获取最新的 Vehicles 并将其加载到 NSMutable Array
中调用(void)RefreshVehicles
, 这将更新最新的 coordinates
对于将用于更新车辆的每个对象 annotation
.我正在使用 NSNotification
知道什么时候异步网络调用和SQLite
更新车辆记录的工作已经完成。当通知触发时,我将删除任何现有车辆 annotations
然后更新本地车辆 NSMutable Array
, 通过调用 addVehiclesToMap
添加新的 annotations
到 map :
//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#pragma mark Notification Listener
//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- (void)RefreshVehicles:(NSNotification *)notif {
NSLog(@"++++++++++++++++++++++++++++++++++++++++ Vehicles UPDATED!");
** POST SOLUTION REMARK: MOVED REMOVE ANNOTATION LOGIC TO: (void)addVehiclesToMap
//** MOVED //If it already Exists, Remove it, Must redraw vehicles because they are moving.
//** MOVED for (id <MKAnnotation> annotation in self.mapView.annotations)
//** MOVED{
//** MOVED//Only Remove Vehicles, Leave Stations, they are static
//** MOVED if ([annotation isKindOfClass:[VehicleAnnotation class]])
//** MOVED{
//** MOVED [self.mapView removeAnnotation:annotation];
//** MOVED}
//** MOVED}
//Load Vehicle Collection
self.vehicleCollection = [[VehicleModelDataController defaultVehicleModelDataController] vehicleReturnAll];
[self addVehiclesToMap];
}
这是 addVehiclesToMap
的方法:**发布解决方案备注:实现 Anna 的解决方案更新 map 后 annotations
在 Main Thread
上,我开始收到以下错误:*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x16d94af0> was mutated while being enumerated.
'
这是因为我正在从后台线程上的计时器刷新中删除注释。为了解决这个问题,我实现了 [self.mapView removeAnnotation:annotation];
也到主线程。**
/*
----- VEHICLES -----
*/
- (void)addVehiclesToMap {
//If it already Exists, Remove it, Must redraw vehicles because they are moving.
for (id <MKAnnotation> annotation in self.mapView.annotations)
{
//Only Remove Vehicles, Leave Stations, they are static
if ([annotation isKindOfClass:[VehicleAnnotation class]])
{
//Remove Vehicle Annotation to MapView on the Main Thread
dispatch_async(dispatch_get_main_queue(), ^{
[self.mapView removeAnnotation:annotation];
});
}
}
//Loop through Vehicle Collection and generate annotation for each Vehicle Object
for (VehicleModel *vehicle in vehicleCollection) {
//New Vehicle Annotation Instance
VehicleAnnotation *myVehicleAnnotation = [[VehicleAnnotation alloc] init];
myVehicleAnnotation.coordinate = CLLocationCoordinate2DMake([vehicle.vehicleLat doubleValue], [vehicle.vehicleLon doubleValue]);
myVehicleAnnotation.vehicleId = [vehicle.vehicleId stringValue];
myVehicleAnnotation.title = vehicle.vehicleLabel;
myVehicleAnnotation.subtitle = vehicle.vehicleIsTrainDelayed;
**POST SOLUTION REMARK: PER ANNA'S SOLUTION, MOVE addAnnodation TO MAIN THREAD:**
//MODIFIED THIS:** [self.mapView addAnnotation:myVehicleAnnotation];
**//TO THIS:**
//Add Vehicle Annotation to MapView on the Main Thread
dispatch_async(dispatch_get_main_queue(), ^{
[self.mapView addAnnotation:myVehicleAnnotation];
});**
}
接下来是 viewAnnotation
的代码代表:
//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#pragma mark MKAnnotationView Delegate
//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// handle our two custom annotations
//
if ([annotation isKindOfClass:[VehicleAnnotation class]]) /// for Vehicles Only
{
//Important, can't use annotation, this lets the compiler know that the annotation is actually an StationAnnotation object.
VehicleAnnotation *vehicleAnnotation = (VehicleAnnotation *)annotation;
//Reuse existing Annotation
NSString* AnnotationIdentifier = vehicleAnnotation.vehicleId.lowercaseString;
MKPinAnnotationView* pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView)
{
//Set unique annotation identifier exp: 304 (The Vehicles's Unique Number)
NSString* AnnotationIdentifier = vehicleAnnotation.vehicleId.lowercaseString;
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
annotationView.canShowCallout = YES;
NSString *vehicleFlagIcon = [@"map_train_green_" stringByAppendingString:vehicleAnnotation.vehicleId.lowercaseString];
UIImage *flagImage = [UIImage imageNamed:vehicleFlagIcon];
CGRect resizeRect;
resizeRect.size = flagImage.size;
CGSize maxSize = CGRectInset(self.view.bounds,
[VehicleMapViewController annotationPadding],
[VehicleMapViewController calloutHeight]).size;
maxSize.height -= self.navigationController.navigationBar.frame.size.height + [VehicleMapViewController calloutHeight];
if (resizeRect.size.width > maxSize.width)
resizeRect.size = CGSizeMake(maxSize.width, resizeRect.size.height / resizeRect.size.width * maxSize.width);
if (resizeRect.size.height > maxSize.height)
resizeRect.size = CGSizeMake(resizeRect.size.width / resizeRect.size.height * maxSize.height, maxSize.height);
resizeRect.origin = (CGPoint){0.0f, 0.0f};
UIGraphicsBeginImageContext(resizeRect.size);
[flagImage drawInRect:resizeRect];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
annotationView.image = resizedImage;
annotationView.opaque = NO;
NSString *vehicleLogo = [@"map_train_green_" stringByAppendingString:vehicleAnnotation.vehicleId.lowercaseString];
UIImageView *sfIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:vehicleLogo]];
annotationView.leftCalloutAccessoryView = sfIconView;
return annotationView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
接下来我确实有删除然后重新添加 annotations
的逻辑使用以下代表。这些代表工作得很好,但需要用户与屏幕交互。我正在尝试每 X 秒刷新一次 map 。到目前为止,可以看到对 annotation
的任何更改位置,我必须触摸屏幕并移动 map 以调用这些删除。我仍然无法在不进行交互的情况下看到车辆自主移动。
发布解决方案备注:我删除了这些代表,因为他们正在对车辆注释执行不必要的更新,当触摸和移动 map 时,图标会闪烁...让计时器完成工作
**// DELETED** -(void)mapView:(MKMapView *)theMapView regionWillChangeAnimated:(BOOL)animated { ...Annotation tear down and rebuild code here }
**//DELETED** -(void)mapView:(MKMapView *)theMapView didUpdateUserLocation:(MKUserLocation *)userLocation { ...Annotation tear down and rebuild code here }
这里我什至接近解决方案了吗?提前致谢...
最佳答案
尝试在主线程上调用 addAnnotation
,这样 UI 更新就不会延迟:
dispatch_async(dispatch_get_main_queue(), ^{
[self.mapView addAnnotation:myVehicleAnnotation];
});
一个不相关的建议:
您无需删除并重新添加车辆注释,只需更新现有车辆的 coordinate
属性, map View 将自动移动注释 View 。这可能会导致稍微更平滑的效果,尽管实现逻辑会稍微困难一些(例如,您需要在 map View annotations
数组中找到现有的车辆注释并更新它,而不是创建一个新的VehicleAnnotation
)。您还必须考虑新车辆并删除不再存在的车辆的注释。
另一个不相关的建议:
而不是这种迂回和神秘的方式来设置坐标:
NSString *coord = [NSString stringWithFormat:@"{%@,%@}",
[NSString stringWithFormat:@"%@", vehicle.vehicleLat],
[NSString stringWithFormat:@"%@", vehicle.vehicleLon]];
CGPoint point = CGPointFromString(coord);
myVehicleAnnotation.coordinate = CLLocationCoordinate2DMake(point.x, point.y);
我建议采用这种更直接、更隐蔽的方法:
myVehicleAnnotation.coordinate = CLLocationCoordinate2DMake(
[vehicle.vehicleLat doubleValue], [vehicle.vehicleLon doubleValue]);
关于ios - MapKit - 更新 MapView 以通过计时器显示移动注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21446917/
我想在我的应用程序中显示 map 上两点之间的点对点路线。我正在使用 MKDirectionsRequest为此。我试图找到浦那到孟买之间的路线。我收到一个错误作为响应。 错误消息: Error Do
我想我可能在 iOS 6 的 mapkit API 中发现了一个错误,但由于我仍然认为自己是新手,我想我会在这里查看是否有人能指出我可能做错的事情。 我有一个应用程序已经工作了几个星期,其中有一个 m
这是我的第一个程序。而且,我正在实现 MapKit。以下是代码: import UIKit import MapKit class ViewController: UIViewController {
如何从 MapkitView 获取当前可见叠加层的列表(数组)? 背景 - 例如,我想在我的 mapkitview 上显示指向某些覆盖类型中心的方向箭头,但是如何获得可见的箭头?我看似乎没有办法做到这
我使用了 Apples WWDC 2017 的项目 tandm - 237“Mapkit 中的新功能”。 已经有一个带数组的data.plist命名的自行车和额外的词典有四个项目(键:值 - 对)。
我正在使用 iOS 11 集群,它工作得很好,基本上你只需要将标识符添加到 MKAnnotationView 的 clusteringIdentifier 属性。 一切正常,但我有一个问题,当用户从
我有一个MKMapView,在顶部有一个UISearchBar,我希望用户能够键入一个地址,并找到该地址并在其上放一个别针。我不知道如何将地址字符串转换为经度和纬度,因此我可以创建一个CLLocati
我想在 map 上画一条路线。 但不使用委托(delegate)的结构。 struct MapView : UIViewRepresentable { } func mapView(_ mapView
绘制的折线显示在建筑物下方。 如何使折线位于所有图层的顶部 请建议 将折线添加为 var coordinates = locationsArrToAdd.map({ (location: CLL
我有一个简单的 Mac 应用程序,不打算用于任何类型的分发;只是个人使用。该应用程序是 NSWindow其中包含一个 MKMapView .由于我没有 Mac 开发人员帐户,也不想要(请参阅“仅供个人
这是一个非常简单的问题。在 MapKit JS 中,如何将注释设置为选中的注释? 我已经在 map View 上有了注释并且可以访问我想要选择的注释。我觉得应该有一个类似于 MapKit 的方法(不是
我可以在我的应用程序中使用 Google map 街景吗? 最佳答案 不。 [填充字符以克服可疑的最小值] 关于xcode - MapKit 是否允许街景?,我们在Stack Overflow上找到一
我有一个功能,可以将注释放大到 map 上的一半,以及用户的位置,这样两者都可以在屏幕上看到。是否有显示其“内容”的注释方法,即模拟按下它?它在放大后立即弹出是理想的选择。 提前致谢。 最佳答案 您可
在我的应用程序中,我添加了很多引脚,并在 viewForAnnotaion 中,我在 MKPinAnnotaionView 上设置了 animatesDrop=TRUE。问题是,当有 200 多个引脚
我已经为此苦苦挣扎了几天,我什至重写了一半的代码来尝试另一种方式。 我从 csv 导入了注释,并用图 block 和副标题放置在 map 上,我徒劳地尝试添加一个标签来公开按钮,以便我可以看到点击了哪
我按照本教程制作了我的第一个应用程序: http://icodeblog.com/2009/12/21/introduction-to-mapkit-in-iphone-os-3-0/ 我真的很想知道
我是 iPhone 开发新手。我在 map 上添加了注释。我能够在 didSelectAnnotationView() 中捕获注释上的点击事件。但我想在用户点击注释时更改注释的图像。 最佳答案 设置图
所以我的 map 上散布了一堆注释...一切都很漂亮。现在我需要能够设置 map 的位置和缩放,以便它们完美契合。我怎样才能做到这一点? 最佳答案 来自苹果论坛... - (void)recenter
我是 iPhone 版 MapKit 的新手,尝试实现此功能,由于某种原因我看不到当前位置蓝点,其他人也有这个问题吗??? #import "DetailMapViewController.h" #i
我有一张显示多个注释的 map 。我想模仿“照片”内置应用程序(iOS 4)上“位置”选项卡的行为,其中当用户更改缩放级别时,注释会自动连接在一起或分开。 我该怎么做? 谢谢! 最佳答案 “照片”应用
我是一名优秀的程序员,十分优秀!