Switch statement nested format - which is correct? - ios

I often use nested cases and I wrap them with { }. My question is which of these are correct? Both seems to work fine.
switch (yourMom) {
case 1: {
// so fat
}
break;
default:
break;
}
OR
switch (yourMom) {
case 1: {
// so fat
break;
}
default:
break;
}

Both are equivalent.
The braces are merely defining scope, and break is not subject to scoping.
For what it's worth, I tend to use the first of your two cases; as it's a little clearer to the reader that the case labels do not follow through to each other.
(You'd need the braces if case 1 for example was declaring a variable.)

Related

Swift 5 - Enum inside of enum

I'm trying to use enum to classify items. As such, I've ended up with having enums inside of enums. And I'm not entirely sure on how this whole enum thing works.
But what I want to do is tap into the enum MaterialClassification, and then if theres a second enum, like in case clay, tap into that enum's value to return it as a string.
enum MaterialClassification {
case clay(value: Clay)
case flux//(value: Fluxs)
case glassFormer
case stain//(value: Clay)
case accessoryMaterial
case all//(value: Clay)
}
extension MaterialClassification {
var materiaIdentifier: String {
switch self {
case .clay:
return "clay"
case .flux:
return "flux"
case .glassFormer:
return "glassFormer"
case .stain:
return "stain"
case .accessoryMaterial:
return "accessoryMaterial"
case .all:
return "all"
}
}
}
enum Clay {
case iskaolin// = "Kaolin"
case isPrimaryKaolin// = "Primary Kaolin"
case isSecondaryKaolin //= "Secondary Kaolin"
case isBallClay //= "Ball Clay"
case isStoneware// = "Stoneware"
case isFireClay //= "Fire Clay"
case isEarthenware// = "Earthenware"
case isVolcanicClay// = "Volcanic"
}
extension Clay {
var clayType: String {
switch self {
case .iskaolin:
return "Kaolin"
case .isPrimaryKaolin:
return "Primary Kaolin"
case .isSecondaryKaolin:
return "Secondary Kaolin"
case .isBallClay:
return "Ball Clay"
case .isStoneware:
return "Stoneware"
case .isFireClay:
return "Fire Clay"
case .isEarthenware:
return "Earthenware"
case .isVolcanicClay:
return "Volcanic Clay"
}
}
}
My goal is to be able to return the nested string when needed. For example:
materialClassification: MaterialClassification.clay(type: Clay.isPrimaryKaolin)
I need a way to return "Primary Kaolin". But I can't figure out how to connect the 2 enums.
If I understand your question correctly, you want to access associated types' properties. You can add a new property to your MaterialClassification enum and use it to access your cases.
Something like this should work
var type: String? {
switch self {
case .clay(let clay):
return clay.clayType
case .flux(let flux):
return flux.fluxType
case .stain(let stain):
return stain.stainType
case .glassFormer, .accessoryMaterial, .all:
return nil
}
}

Delegate or closure for multiple event in same object

There is
var tableView: MyTableView?
tableView?.onGoToA = {
self.goToA()
}
tableView?.onGoToB = {
self.goToB()
}
tableView?.onGoToC = {
self.goToC()
}
are there better way for this case or better that just use delegate?
If you have limited possible cases, I would have single closure that takes a enum as an argument and will have a switch case to decide which method to trigger
If each event has a value associated with it you can exploit enums with associated values as well :)
Example:
enum EventType {
case toA
case toB
case toC
}
Declare your closure as
var routerBlock: ((EventType) -> ())? = nil
Finally have router block implemented as
tableView?.routerBlock = {[weak self] (eventType) in
switch eventType {
case .toA:
self?.gotoA()
case .toB:
self?.goToB()
case .toC:
self?.goToC()
}
}
You can use the similar approach with delegates as well. Rather than having 3 delegate methods you can have one method which takes EventType and have the same switch block to decide which method to trigger
Hope this helps

Keyword "Protocol" as function parametr [duplicate]

Basically, I want to set up a function that uses 'for' as a parameter for readability.
enum Genre {
case drama
case comedy
}
func setupTable(for: Genre) {
switch for {
case .drama: break
case .comedy: break
}
}
I set something like this up but when i try and use the switch for 'for' it comes up as a keyword and throws a compile error.
Cheers
When using a keyword as a normal identifier you have to escape it using backticks ` like this
func setupTable(for: Genre) {
switch `for` {
case .drama: break
case .comedy: break
}
}
On a side note, as pointed out by #Hamish in a comment on the question, you should try to avoid using such names for variables, which (in this case) you can do by providing both an internal and external name for the parameter:
func setupTable(for genre: Genre) {
switch genre {
case .drama: break
case .comedy: break
}
}

Swift enum function for only a single case of the enum?

I want to declare a function which I can only use for a single specific enum case.
For example I have CustomTextFieldTypes enum. This has the following cases and functions.
enum CustomTextFieldTypes {
case CardType
case CardNumber
case CardExpiryDate
case CardName
case CCVNumber
func inputCardNumber(cardNumber: String!, cardNumberTextField: XCUIElement?) {
cardNumberTextField?.typeText(cardNumber)
}
func inputCardCCVNumber(cardCCVNumber: String!, cardCCVNumberTextField: XCUIElement?) {
cardCCVNumberTextField?.typeText(cardCCVNumber)
}
}
Now I want to call the inputCardNumber(...) function only for the CustomTextFieldTypes.CardNumber case. I can do the following...
CustomTextFieldTypes.CardNumber.inputCardNumber(...)
But at the same time I can do this...
CustomTextFieldTypes.CardExpiryDate.inputCardNumber(...) or
CustomTextFieldTypes.CardNumber.inputCardNumber(...)
I only want to call the inputCardNumber(...) function for the CardNumber case. Not from another case the enum itself. How do I achieve this?
Thanks in advance for any help
EDIT- Here's some background on what I'm doing. I was writing a UI test which would input text into text fields. I wanted to keep the input code away from my test file and I started "Experimenting" with enums and enum functions. I was wondering if I could have a function explicitly available for an enum case. Judging from the comments I cannot do this (I checked online but didn't get far). It's not a bad architecture or anything, I was just splitting up test code..
Thanks for everyone for replying.
You can perform a switch on self in order to execute certain code for certain cases. Here's an example:
enum CustomTextFieldTypes {
case cardType
case cardNumber
case cardExpiryDate
case cardName
case ccvNumber
func inputCardNumber(cardNumber: String!, cardNumberTextField: XCUIElement?) {
switch self {
case .cardNumber:
cardNumberTextField?.typeText(cardNumber)
default:
return
}
}
}
No need to use a switch when you only want to match a single case:
enum CustomTextFieldTypes {
case cardType
case cardNumber
case cardExpiryDate
case cardName
case ccvNumber
func inputCardNumber(cardNumber: String!, cardNumberTextField: XCUIElement?) {
if case .cardNumber = self {
cardNumberTextField?.typeText(cardNumber)
}
}
}
Dont know exactly why are XCUIElements needed but do something like this
//MARK: Declaration
enum CustomTextFieldTypes {
case CardType(String)
case CardNumber(String)
case CardExpiryDate(String)
case CardName(String)
case CCVNumber(String)
}
//MARK: Definition
var cardNumber = CustomTextFieldTypes.CardNumber("123")
var cardExpiry = CustomTextFieldTypes.CardExpiryDate("10-10-2016")
//MARK: Usage
func useCard(type: CustomTextFieldTypes)
{
switch type {
case .CardNumber(let numberString):
print(numberString)
case .CardType(let cardtype):
print(cardtype)
case .CardExpiryDate(let expiryDate):
print(expiryDate)
case .CardName(let name):
print(name)
case .CCVNumber(let ccvnumber):
print(ccvnumber)
}
}
useCard(cardNumber)
useCard(cardExpiry)
If you really neeed XCUIElement then change case CardType(String) to case CardType(String, XCUIElement) and update all the other code as well

How do I randomize methods?

I have 4 void statements and I want to randomize them so one out of the 4 triggers at a time. Like for example the first void triggers then the next time maybe the third void triggers and so fourth. Could I use arc4random() or do I need another approach?
Sure you can use arc4Random. (It's better to use arc4random_uniform, as #JustSid pointed out in his comments. Off to fix my sample code...) There are a nearly infinite number of ways to do this.
First, a gripe of mine. Don't call methods "voids". That's inaccurate and misleading. (And it makes you sound ignorant about programming.) They're methods. The text inside the parenthesis at the beginning of the method tells you what kind of value it returns. If it doesn't return anything, the word "void" is C language notation for "nothing."
So the method:
-(void) foo;
Takes no parameters and doesn't return anything, where the method:
-(BOOL) bar;
...also takes no parameters, but it returns a boolean result.
The first method is not a "void". It is a method that doesn't return a result.
Now, to your question:
You could do something like this:
- (void) foo;
{
NSLog(#"foo");
}
- (void) bar;
{
NSLog(#"bar");
}
- (void) foobar;
{
NSLog(#"foobar");
}
- (void) randomMethod;
{
int index = arc4random_uniform(3);
switch (index)
{
case 0:
[self foo];
break;
case 1:
[self bar];
break;
case 2:
[self foobar];
break;
}
}
You could also use blocks. You could set up an array of block pointers, use arc4random_uniform() to pick an array index, and execute the appropriate block from the array. (Blocks are objects so you can add them to an array.)
The syntax of blocks and block pointers is a little tricky to follow, so for simplicity I'm not going to write that out. If you're interested I can amend my answer to show how that's done.
arc4random() is perfect for that.
int a = arc4random() % 4;
switch (a) {
case 0:
[self void0];
break;
case 1:
[self void1];
break;
// ...
}
For a scalable solution, you can use NSSelectorFromString.
The NSSelectorFromString will generate this warning: "performSelector may cause a leak because its selector is unknown". If you can't live with the warning, there are solution for that.
NSArray *methods = #[#"method1", #"method2", #"method3", #"method4"]; //add more if needed
int index = arc4random_uniform((int)methods.count);
NSString *selectedMethod = [methods objectAtIndex:index];
SEL s = NSSelectorFromString(selectedMethod);
[self performSelector:s];
-(void)method1
{
NSLog(#"method1 is called");
}
-(void)method2
{
NSLog(#"method2 is called");
}
-(void)method3
{
NSLog(#"method3 is called");
}
-(void)method4
{
NSLog(#"method4 is called");
}

Resources