-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add back MGLStyleFunction and re-document MGLStyleValue #7943
Conversation
@boundsj, thanks for your PR! By analyzing this pull request, we identified @1ec5 and @friedbunny to be potential reviewers. |
This PR adds back A constraint here is that we don't want to break backwards compatibility with 3.4.x's To do this I:
The main tension point was the
|
@return An `MGLCompositeStyleFunction` object with the given interpolation mode, | ||
composite stops, attribute name, and options. | ||
*/ | ||
+ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode compositeStops:(NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *) *)compositeStops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If each stop is “interpreted as a source function”, should the type of compositeStops
be NSDictionary<id, NSDictionary<id, MGLSourceStyleFunction<T> *> *> *
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was me doing a poor job of trying to clarify the opposite: "composite" in this case means a composite of stops dictionaries not functions (see discussion in #7596 (comment)). In d46559a, I punted on trying to explain this in the class factory method in favor of the explanation in the MGLCompositeStyleFunction
stops
property
platform/darwin/src/MGLStyleValue.h
Outdated
// TODO: API docs | ||
/** | ||
The exponential interpolation base of the function’s interpolation curve. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Document the fact that interpolationBase
may not apply to all style functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
platform/darwin/src/MGLStyleValue.h
Outdated
// TODO: API docs | ||
/** | ||
The exponential interpolation base of the function’s interpolation curve. | ||
*/ | ||
@property (nonatomic) CGFloat interpolationBase; | ||
|
||
@end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For backwards compatibility, MGLStyleFunction also needs the initializers that it had in v3.4.0. These initializers can be marked as deprecated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will probably look a bit strange no matter what we do. I think 406e647 is a workable solution until a semver bump when we can more officially make this class abstract.
The initializers have been brought back and an actual instance of MGLStyleFunction
is created and returned if you use them. The conversion methods have been updated to coerce MGLStyleFunction
instances into MGLCameraStyleFunction
instances with the appropriate interpolation mode. However, documentation attempts to point developers to the MGLStyleValue class factory methods to avoid all of this.
platform/darwin/src/MGLStyleValue.h
Outdated
An `MGLCameraStyleFunction` is a value function defining a style value that changes | ||
as the zoom level changes. The layout and paint attribute properties of an | ||
`MGLStyleLayer` object can be set to `MGLCameraStyleFunction` objects. Use a zoom | ||
level function to create the illusion of depth and control data density. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
“Zoom level functions” are now known as “camera functions”.
Note that this approach technically doesn’t guarantee full backwards compatibility with Swift code: let circleRadius = circleStyleLayer.circleRadius as! MGLStyleFunction<NSNumber>
circleStyleLayer.circleRadius = circleRadius.stops[14] must now be converted to at least something like this: let circleRadius = circleStyleLayer.circleRadius as! MGLStyleFunction<NSNumber>
circleStyleLayer.circleRadius = (circleRadius.stops as! [NSNumber: MGLStyleFunction<NSNumber>])[14] This isn’t a problem in Objective-C, where you can use |
@return An `MGLCameraStyleFunction` object with the given interpolation mode, | ||
camera stops, and options. | ||
*/ | ||
+ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode cameraStops:(NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *)cameraStops options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remember to use the NS_…_OF
macros until we drop iOS 8 support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like we forgot to do this in the 3.4.0
release. In fbb8068 and 3b90d85 I updated the deprecated methods and everything in the resurrected MGLStyleFunction
to use the macro. The only use of NSDictionary
(with no lightweight generic attributes) in MGLStyleValue
now is for the stops
property of MGLStyleFunction
for reasons already discussed in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MGLStyleFunction is going to be a bit messy, sort of like CLRegion (versus CLCircularRegion), for awhile, but I think we have the start of a workable solution.
/** | ||
The modes used to interpolate property values between map zoom level changes or | ||
over a range of feature attribute values. | ||
*/ | ||
@property (nonatomic) MGLInterpolationMode interpolationMode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we avoid effectively adding an interpolationMode
property to MGLStyleFunction that would only sometimes be applicable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In ee89e94 I removed it in MGLStyleFunction
and added it back to the concrete subclasses. This sort of makes sense because an MGLStyleFunction
technically does not (did not) have an interpolation mode. In the future, we should add the property back to MGLStyleFunction
because every actual function class does have an interpolation mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
every actual function class does have an interpolation mode
Ah, I misunderstood. In that case, it’s fine (and preferable) to have it in MGLStyleFunction to avoid duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. For now, it'll be a bit of a lie, but still reasonable.
MGLStyleFunction
's interpolation mode will be exponential even though it did not have such a concept before in 3.4.x. However, any MGLStyleFunction
instance that is put to use in 3.5.0 is treated like a camera function with an exponential interpolation mode so I feel ok about that. I'll put it back on MGLStyleFunction
.
platform/darwin/src/MGLStyleValue.h
Outdated
@param stops A dictionary associating zoom levels with style values. | ||
@return An `MGLStyleFunction` object with the given interpolation base and stops. | ||
*/ | ||
- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops NS_DESIGNATED_INITIALIZER; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you mark this as a designated initializer, does that mean all the subclass initializers have to call this method? Or would removing NS_DESIGNATED_INITIALIZER
be considered a breaking change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, in a future release, we’d end up making all -init…
methods private (as would be expected of class clusters). So we should make all the new -init…
methods (like in MGLCameraStyleFunction
) private and leave this one public but deprecated, for backwards compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you mark this as a designated initializer, does that mean all the subclass initializers have to call this method?
Yes
Or would removing NS_DESIGNATED_INITIALIZER be considered a breaking change?
I don't think so. We never suggested that developers should subclass MGLStyleFunction.
In 7cbeba7, I exposed only MGLStyleFunction's initializer publicly but
deprecated it and removed its designated initializer status. Internally this allows us to ignore the deprecated initializer in subclasses.
platform/darwin/src/MGLStyleValue.mm
Outdated
} | ||
|
||
+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops { | ||
return [[self alloc] initWithInterpolationBase:interpolationBase stops:stops]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we initialize an MGLCameraStyleFunction here instead (and in +functionWithStops:
, but not -init
or -initWithInterpolationBase:stops:
)? If there are warnings associated with the designated initializer, we can suppress the warnings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done 2f414f2
platform/darwin/src/MGLStyleValue.mm
Outdated
} | ||
|
||
- (NSUInteger)hash { | ||
return self.stops.hash + self.interpolationBase; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use @(self.interpolationBase).hash
, not interpolationBase
itself, to further minimize collisions. There are similar problems with interpolationMode
in the subclasses. Feel free to take care of this in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done 1b67069
Expose only MGLStyleFunction's initializer publicly but deprecate it and do not mark it as designated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for flip-flopping on interpolationMode
; based on your explanation in #7943 (comment), it does make sense to declare it on MGLStyleFunction and not each of its subclasses.
Otherwise, this PR looks good to go.
This reverts commit ee89e94.
I'm super lost. let carLayer = MGLSymbolStyleLayer(identifier: "cars-layer", source: carSource)
style.setImage(UIImage(named: "car-red")!, forName: "car-red")
style.setImage(UIImage(named: "car-blue")!, forName: "car-blue")
style.setImage(UIImage(named: "car-silver")!, forName: "car-silver")
style.setImage(UIImage(named: "car-green")!, forName: "car-green")
style.setImage(UIImage(named: "car-orange")!, forName: "car-orange")
carLayer.iconImageName = MGLSourceStyleFunction(
interpolationMode: .identity,
sourceStops: nil,
attributeName: "car-color",
options: [.defaultValue: MGLStyleValue<NSString>(rawValue: "car-silver")]
)
carLayer.iconImageName = MGLCameraStyleFunction(
interpolationMode: .identity,
sourceStops: nil,
attributeName: "car-color",
options: [.defaultValue: MGLStyleValue<NSString>(rawValue: "car-silver")]
) regardless of which one I choose: but I need |
Data-driven styling for iconImageName is not in any released iOS SDK version yet. It'll be in 3.6.0. If you're ever in doubt about SDK compatibility, https://www.mapbox.com/mapbox-gl-js/style-spec/ has support matrixes for every property (albeit you'll need to translate from SDK property name to style spec property name). |
Ahhhhhh. I'll remember this for the future. Thanks! |
The documentation for
The iOS SDK’s documentation comes with a full correspondence table. |
please, when I use Data-driven styling for iconImageName,the Application crash, I want use Data-driven styling for iconImageName,when the 3.6.0. release? |
@wr6524798, this closed pull request isn’t the best place for new bug reports. Please open a new issue about the crash you’re seeing, and be sure to include the crash trace so we can properly diagnose and prioritize the problem. Thank you! |
Fixes: #7934
Addresses
MGLStyleValue
documentation todos noted in #7924:MGLStyleValue
(as a class cluster it represents something different now)