While it is possible with a lot of work to accomplish something very similar to Swift's enums with associated types in Objective-C (see the blog post I linked in a comment above), it requires a bunch of hard-to-comprehend code.
I'd recommend taking a more natural Objective-C style approach. You'll lose out on some of the type safety Swift provides, but ObjC is naturally a less type-safe language.
For example:
// Create an options enum. Bridges into Swift as an OptionSet
typedef NS_OPTIONS(NSInteger, CoffeeOptions) {
CoffeeOptionsBlack = 0,
CoffeeOptionsWithSugar = 1 << 0,
CoffeeOptionsWithCream = 1 << 1
};
// Create a (non-extensible) string-typed "enum". Bridges into Swift as an enum-style struct with string "raw values"
typedef NSString *CoffeeQuantityKey NS_TYPED_EXTENSIBLE_ENUM;
static CoffeeQuantityKey const CoffeeQuantityKeySpoonsOfSugar = @"SpoonsOfSugar";
static CoffeeQuantityKey const CoffeeQuantityKeyTeaspoonsOfCream = @"TeaspoonsOfCream";
@interface CoffeeMachine : NSObject
- (void)makeCoffeeWithOptions:(CoffeeOptions)options quantities:(NSDictionary<CoffeeQuantityKey, NSNumber *> *)quantities;
@end
@implementation CoffeeMachine
- (void)makeCoffeeWithOptions:(CoffeeOptions)options quantities:(NSDictionary<CoffeeQuantityKey, NSNumber *> *)quantities
{
// Make coffee
if (options & CoffeeOptionsWithSugar) {
NSNumber *sugarAmount = quantities[CoffeeQuantityKeySpoonsOfSugar] ?: @1; // Default to 1 spoon
NSLog(@"Adding %@ spoons of sugar", sugarAmount);
}
if (options & CoffeeOptionsWithCream) {
NSNumber *creamAmount = quantities[CoffeeQuantityKeyTeaspoonsOfCream] ?: @1; // Default to 1 teaspoon
NSLog(@"Adding %@ teaspoons of cream", creamAmount);
}
}
@end
This also has the advantage of bridging relatively nicely into Swift:
let cm = CoffeeMachine()
cm.makeCoffee(options: [.withSugar, .withCream], quantities: [.spoonsOfSugar : 3])