#import "MGLSource_Private.h" #import "MGLStyle_Private.h" #import "MGLMapView_Private.h" #import "NSBundle+MGLAdditions.h" #include #include #include @interface MGLSource () // Even though this class is abstract, MGLStyle uses it to represent some // special internal source types like mbgl::AnnotationSource. @property (nonatomic, readonly) mbgl::style::Source *rawSource; @property (nonatomic, readonly, weak) MGLMapView *mapView; @end @implementation MGLSource { std::unique_ptr _pendingSource; } - (instancetype)initWithIdentifier:(NSString *)identifier { if (self = [super init]) { _identifier = identifier; } return self; } - (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource mapView:(MGLMapView *)mapView { NSString *identifier = @(rawSource->getID().c_str()); if (self = [self initWithIdentifier:identifier]) { _rawSource = rawSource; _rawSource->peer = SourceWrapper { self }; _mapView = mapView; } return self; } - (instancetype)initWithPendingSource:(std::unique_ptr)pendingSource { if (self = [self initWithRawSource:pendingSource.get() mapView:nil]) { _pendingSource = std::move(pendingSource); } return self; } - (void)addToMapView:(MGLMapView *)mapView { if (_pendingSource == nullptr) { [NSException raise:MGLRedundantSourceException format:@"This instance %@ was already added to %@. Adding the same source instance " \ "to the style more than once is invalid.", self, mapView.style]; } _mapView = mapView; _mapView.style.rawStyle->addSource(std::move(_pendingSource)); } - (BOOL)removeFromMapView:(MGLMapView *)mapView error:(NSError * __nullable * __nullable)outError { BOOL removed = NO; if (self.rawSource == mapView.style.rawStyle->getSource(self.identifier.UTF8String)) { auto removedSource = mapView.style.rawStyle->removeSource(self.identifier.UTF8String); if (removedSource) { removed = YES; _pendingSource = std::move(removedSource); _mapView = nil; } else if (outError) { NSString *format = NSLocalizedStringWithDefaultValue(@"REMOVE_SRC_FAIL_IN_USE_FMT", @"Foundation", nil, @"Source '%@' is in use, cannot remove.", @"User-friendly error description"); NSString *localizedDescription = [NSString stringWithFormat:format, self.identifier]; *outError = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeSourceIsInUseCannotRemove userInfo:@{ NSLocalizedDescriptionKey : localizedDescription }]; } } else if (outError) { // Consider raising an exception here NSString *format = NSLocalizedStringWithDefaultValue(@"REMOVE_SRC_FAIL_MISMATCH_FMT", @"Foundation", nil, @"Identifier '%@' does not match source identifier '%s'", @"User-friendly error description"); NSString *localizedDescription = [NSString stringWithFormat:format, self.identifier, self.rawSource ? self.rawSource->getID().c_str() : "(null)"]; *outError = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeSourceIdentifierMismatch userInfo:@{ NSLocalizedDescriptionKey : localizedDescription }]; } return removed; } - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p; identifier = %@>", NSStringFromClass([self class]), (void *)self, self.identifier]; } @end