Custom Class Clusters in Swift

Custom class clusters in Swift

I don't believe that this pattern can be directly supported in Swift, because initialisers do not return a value as they do in Objective C - so you do not get an opportunity to return an alternate object instance.

You can use a type method as an object factory - a fairly contrived example is -

class Vehicle
{
var wheels: Int? {
get {
return nil
}
}

class func vehicleFactory(wheels:Int) -> Vehicle
{
var retVal:Vehicle

if (wheels == 4) {
retVal=Car()
}
else if (wheels == 18) {
retVal=Truck()
}
else {
retVal=Vehicle()
}

return retVal
}

}

class Car:Vehicle
{
override var wheels: Int {
get {
return 4
}
}
}

class Truck:Vehicle
{
override var wheels: Int {
get {
return 18
}
}
}

main.swift

let c=Vehicle.vehicleFactory(4)     // c is a Car

println(c.wheels) // outputs 4

let t=Vehicle.vehicleFactory(18) // t is a truck

println(t.wheels) // outputs 18

Proper subclassing of class clusters

You've reached the classic double-inheritance problem. You want to be either a RedUIView or GreenUIView and be either a MyUIViewiOS6 or a MyUIViewiOS7 view.

Since objective-c does not support double-inheritance, you'll have to decide the difference between what you are, and how you act. Anything that determines what you are, you put in the class. Anything that determines how you act goes into a @protocol which then can be implemented.

I would subclass MyUIView since MyUIViewiOS6 and MyUIViewiOS7 correspond to who you are, and then implement a Red or Green protocol for certain functionality:

@interface MyRedUIView : MyUIView<RedProtocol> @end

You can check to see if this class conforms to a specific protocol:

 if ([class conformsToProtocol:@protocol(RedProtocol)]) {
self.color = [UIColor redColor];
}

If both of them really are who you are, then you have to use four separate classes.


Here's an example using categories. Assuming that you have MyUIView as specified in the question:

GreenView.h

#import "MyUIView.h"
#import "Green.h"

@interface MyUIView (GreenUIView) <Green>

-(BOOL) isGreen;

@end

@interface GreenView : MyUIView @end

GreenView.m

#import "GreenView.h"

@implementation MyUIView (GreenUIView)

-(BOOL) isGreen{
return [self conformsToProtocol:@protocol(Green)];
}
@end

@implementation GreenView @end

Green.h

@protocol Green <NSObject> @end

AppDelegate.m

#import "GreenView.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
GreenView* view = [[GreenView alloc] init];
NSLog(@"%@", [view isGreen]?@"yes":@"no");
return YES;
}

@end

How can i parse a custom marker icon with clustering in iOS Swift

Solution found:Here starts the class in GMUDefaultClusterRenderer.m at clustering folder

 - (GMSMarker *)markerWithPosition:(CLLocationCoordinate2D)position
from:(CLLocationCoordinate2D)from
userData:(id)userData
clusterIcon:(UIImage *)clusterIcon
animated:(BOOL)animated {.....

......

I replace the original with this:

  if (clusterIcon != nil) {
marker.icon = clusterIcon;
marker.groundAnchor = CGPointMake(0.5, 0.5);
}else{
marker.icon = [UIImage imageNamed:@"K_Annotation.png"];
}

Can I create a class that subclasses from Array?

You can add methods to Array via an extension. Something like:

extension Array
{
func randomObject() -> Element { return self[ Int( arc4random_uniform( UInt32( self.count ) ) ) ] }
}

Now you can do myArray.randomObject() where myArray is of type Array


Edit: Also, @Addison correctly pointed out that struct types cannot be subclassed in Swift.

Objective-C and Class Cluster pattern

Basically, the instance you have allocated could be thrown away and replaced with a different instance. Technically, this isn't specific to class clusters and that is why when you call super in any init method you need to set the result as self:

self = [super init];

Is it possible to customize cluster image in iOS 11?

You should check to see if the annotation is of type MKClusterAnnotation. If it is you can then use the memberAnnotations property to access the member annotations. In your case, for example, you could say:

override var annotation: MKAnnotation?
{
willSet
{
if let cluster = newValue as? MKClusterAnnotation {
image = UIImage(named: "Cluster")
} else {
// set image for non cluster
}
}
}

For more information see WWDC 2017 What's New with MapKit.

Inherit from class with private initializer?

There are various ways to solve this issue:

  1. Declare the initializer as internal, that will give you module access and your subclass will be able to call it.

  2. Declare the classes in the same file, then private won't be an issue anymore (private enables access from the same file).

  3. Instead of abstract classes, you can make MapItem a protocol and ClusterItem and Cluster could inherit from GMSMarker directly. However, this solution may not be good depending on your exact needs.

Make initializer for superclass return a specific subclass?

It's playing fast and loose with inheritance having the parent class know about its subclasses (very poor anti-pattern!) but this would work...

class Measurement {
var unitString : String

class func factory(unknownUnit: String) -> Measurement {
if unknownUnit == "kg" {
return Mass(myUnit: unknownUnit)
} else { // Random default, or make func return Measurement? to trap
return Volume(myUnit: unknownUnit)
}
}

init(myUnit: String) {
// checks if the unit is either Volume or Mass, and returns an instance of that class
self.unitString = myUnit
}
}

class Volume : Measurement {
}

class Mass : Measurement {
}

let mass = Mass(myUnit: "kg") // class: Mass
let volume = Volume(myUnit: "ml") // class: Volume
let shouldntBeVolume = Measurement(myUnit: "ml") // class: Measurement
let shouldntBeMass = Measurement(myUnit: "kg") // class: Measurement
let isVolume = Measurement.factory("ml") // class: Volume
let shouldBeMass = Measurement.factory("kg") // class: Mass


Related Topics



Leave a reply



Submit