Classes for representing teleconferencing numbers

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
2
down vote
favorite
I'm developing an app that joins tele-conference calls so we use conference numbers a lot. I've got this basic structure to encapsulate the information regarding a conference number.
///A model that represents a teleconference number.
struct ConferenceNumber
let iso : String ///Interntational Standardised 2 letter Abbreviation for country.
let conferenceProvider: ConferenceProvider ///The company that hosts the conference call the number is for.
let number : String ///The phone number
let toll : Bool ///Whether the number is a paid or free line.
let country: String
init(ISO: String, country: String, number:String, provider: ConferenceProvider, toll: Bool)
self.iso = ISO
self.country = ConferenceNumber.localeName(from: ISO) ?? country
self.number = number
self.conferenceProvider = provider
self.toll = toll
I'm running in to two problems:
This class if often bypassed in favour of storing the numbers in
[String]arrays. I can't think of a nice way to put this in to an object asConferenceNumber.numberdoesn't sound right.The
conferenceProviderproperty has resulted in over a dozen switch statement in our code base which all look similar to the code below. Is it possible to reduce repeating myself this often with protocols or subclasses?
ConferenceProvider enum
///Defines the type of conference call service the meeting uses if any.
public enum ConferenceProvider : String
case unknown = "",
zoom = "Zoom",
att = "AT&T",
webex = "WebEx",
arkadin = "Arkadin"
Class with ConferenceProvider switch statements example
import Foundation
///Builds, stores, retrieves and queries conference number directories.
class ConferenceNumberDirectory
static let att: [ConferenceNumber] =
return buildDirectory(for: .att, from: jsonArray)
()
static let arkadinMeetings: [ConferenceNumber] =
return buildDirectory(for: .arkadinMeetings, from: jsonArray)
()
static let webex: [ConferenceNumber] =
return buildDirectory(for: .webex, from: jsonArray)
()
static let zoom: [ConferenceNumber] =
return buildDirectory(for: .zoom, from: jsonArray)
()
static let allProviders: [ConferenceNumber] =
return att + arkadinMeetings + webex + zoom
()
static let attPhoneNumbers: [String] =
return ConferenceNumberDirectory.att.map( $0.number )
()
static let arkadinMeetingsPhoneNumbers: [String] =
return ConferenceNumberDirectory.arkadinMeetings.map( $0.number )
()
static let webexPhoneNumbers: [String] =
return ConferenceNumberDirectory.webex.map( $0.number )
()
static let zoomPhoneNumbers: [String] =
return ConferenceNumberDirectory.zoom.map( $0.number )
()
static let allPhoneNumber: [String] =
return ConferenceNumberDirectory.allProviders.map $0.number
()
private static let jsonArray: [Any]? =
guard let numbersFilePath = Bundle.main.path(forResource: "numbers", ofType:"json") else
return nil
let data = try! Data(contentsOf: URL(fileURLWithPath:numbersFilePath), options: .uncached)
return try! JSONSerialization.jsonObject(with: data) as? [Any]
()
///Takes the outputted [Any]? from a JSON file and builds an Array of ConferenceNumber objects suitable for Call In to use.
static func buildDirectory(for conferenceProvider: ConferenceProvider, from jsonArray: [Any]?) -> [ConferenceNumber]
var directory = [ConferenceNumber]()
do
guard let rootJSONArray = jsonArray else
throw SerializationError.missing("JSON Root")
for entry in rootJSONArray
guard let dictionary = entry as? [String: Any] else
throw SerializationError.missing("JSON Root")
guard let isoCode = dictionary["ISO Code"] as? String else
throw SerializationError.missing("isoCode")
guard let country = dictionary["Country"] as? String else
throw SerializationError.missing("country")
if let key = getTollKey(for: conferenceProvider), let tollNumbers = try self.extractNumbers(from: dictionary, forKey: key)
directory.append(contentsOf: tollNumbers.mapConferenceNumber(ISO: isoCode, country: country, number: $0, provider: conferenceProvider, toll: true) )
if let key = getTollFreeKey(for: conferenceProvider), let tollFreeNumbers = try self.extractNumbers(from: dictionary, forKey: key)
directory.append(contentsOf: tollFreeNumbers.mapConferenceNumber(ISO: isoCode, country: country, number: $0, provider: conferenceProvider, toll: false))
catch let error
print(error)
return directory
///Returns the directory for a given conference provider. Returns all if no numbers exist for this provider.
static func getDirectory(for conferenceProvider: ConferenceProvider) -> [ConferenceNumber]?
switch conferenceProvider
case .arkadinMeetings:
return ConferenceNumberDirectory.arkadinMeetings
case .att:
return ConferenceNumberDirectory.att
case .webex:
return ConferenceNumberDirectory.webex
case .zoom:
return ConferenceNumberDirectory.zoom
default:
return ConferenceNumberDirectory.att + ConferenceNumberDirectory.arkadinMeetings + ConferenceNumberDirectory.webex + ConferenceNumberDirectory.zoom
/**
Returns a ConferenceNumber that matches the phone number and the country ISO code provided. Returns nil if no number is found.
- parameter number: The phone number to try and find a match for
- parameter isoCode: The international standard organizations 2 digit code that represents a country for all known languages
At present we do not store ConferenceNumber Objects in the settings so we often need to convert the Strings we store back in to their original conference number. Where we to save the object we would still need this as user entered numbers will not contain all ConferenceNumber properties.
*/
static func findConferenceNumber(usingNumber number: String, andISOCode isoCode: String?, fromDirectory conferenceProvider: ConferenceProvider = .unknown) -> ConferenceNumber?
if number.isEmpty
/**
Returns all conference numbers that share the same number.
Similarly as the previous one, findConferenceNumber() but getting all possibilities because we know that some countries share the same number, example: 8884266840
*/
static func findConferenceNumbers(usingNumber number: String, fromDirectory conferenceProvider: ConferenceProvider? = .unknown) -> [ConferenceNumber]
if number.isEmpty
return
switch conferenceProvider
case .att?:
return ConferenceNumberDirectory.att.filter( $0.number == number)
case .arkadinMeetings?:
return ConferenceNumberDirectory.arkadinMeetings.filter($0.number == number)
case .webex?:
return ConferenceNumberDirectory.webex.filter( $0.number == number)
case .zoom?:
return ConferenceNumberDirectory.zoom.filter($0.number == number)
default:
let allConferenceNumbers = ConferenceNumberDirectory.att + ConferenceNumberDirectory.arkadinMeetings + ConferenceNumberDirectory.webex + ConferenceNumberDirectory.zoom
return allConferenceNumbers.filter($0.number == number)
///Find the provider for a given number, return unknown if the number does not exist
///- warning: This will return the first provider that has the current number seeing as providers don't share numbers.
static func findProvider(forNumber queriedNumber: String) -> ConferenceProvider
return ConferenceNumberDirectory.allProviders.first $0.number == queriedNumber ?.conferenceProvider ?? .unknown
///Returns an array of all country iso codes a queriedNumber is used by.
static func findCountryISOCodes(forNumber queriedNumber: String) -> [String]
return ConferenceNumberDirectory.allProviders.filter $0.number == queriedNumber .map( $0.iso )
///Extracts telephone numbers from a given dictionary and key by taking the value as a string then returning an array of each comma seperated component of that string.
private static func extractNumbers(from dictionary: [String: Any], forKey key: String?) throws -> [String]?
guard let jsonKey = key ,let tollNumbersString = dictionary[jsonKey] as? String else
throw SerializationError.missing(key ?? "key is nil")
if tollNumbersString.isEmpty
return nil
return tollNumbersString.components(separatedBy: ",")
///Returns the JSON key to access a given ConferenceProviders toll numbers.
private static func getTollKey(for provider: ConferenceProvider) -> String?
switch provider
case .att:
return "AT&T toll"
case .arkadinMeetings:
return "arkadin Meetings toll"
case .webex:
return "Webex toll"
case .zoom:
return "Zoom toll"
default:
return nil
///Returns the JSON key to access a given ConferenceProviders toll-free numbers.
private static func getTollFreeKey(for provider: ConferenceProvider) -> String?
switch provider
case .att:
return "AT&T toll-free"
case .arkadinMeetings:
return "arkadin Meetings toll-free"
case .webex:
return "Webex toll-free"
default:
return nil
Class with ConferenceProvider switch statements Example 2
/// Data class, responsible for storing and retrieving of user settings.
import Foundation
class Settings
/// init user defaults with the app group suite to be able to use the same values in the app and in the widget
static let defaults = SharedGlobals.appGroupDefaults
static var id: String?
get return self.defaults.string(forKey: "id")
set self.defaults.set(newValue, forKey: "id")
static var attNumber: String?
get return self.defaults.string(forKey: "attNumber")
set self.defaults.set(newValue, forKey: "attNumber")
static var attCountry: String?
get return self.defaults.string(forKey: "attCountry")
set self.defaults.set(newValue, forKey: "attCountry")
static var attISO: String?
get return self.defaults.string(forKey: "attISO")
set self.defaults.set(newValue, forKey: "attISO")
static var attHostCodes: [String]
get if let codes = self.defaults.stringArray(forKey: "hostCodes")
return codes
else
return
set self.defaults.set(newValue, forKey: "hostCodes")
///AT&T participant codes, these are paired to hostcodes (by index) so we can determine which host code to use via parsed participant codes.
static var attParticipantCodes: [String]
get if let codes = self.defaults.stringArray(forKey: "participantCodes")
return codes
else
return
set self.defaults.set(newValue, forKey: "participantCodes")
///arkadinMeetings (Smartcloud)
static var arkadinMeetingsCountry: String?
get return self.defaults.string(forKey: "arkadinMeetingsCountry")
set self.defaults.set(newValue, forKey: "arkadinMeetingsCountry")
static var arkadinMeetingsNumber: String?
get return self.defaults.string(forKey: "arkadinMeetingsNumber")
set self.defaults.set(newValue, forKey: "arkadinMeetingsNumber")
static var arkadinMeetingsISO: String?
get return self.defaults.string(forKey: "arkadinMeetingsISO")
set self.defaults.set(newValue, forKey: "arkadinMeetingsISO")
static var arkadinMeetingsModeratorCode: String?
get return self.defaults.string(forKey: "arkadinMeetingsModeratorCode")
set self.defaults.set(newValue, forKey: "arkadinMeetingsModeratorCode")
///WEBEX
static var webexNumber: String?
get return self.defaults.string(forKey: "webexNumber")
set self.defaults.set(newValue, forKey: "webexNumber")
static var webexCountry: String?
get return self.defaults.string(forKey: "webexCountry")
set self.defaults.set(newValue, forKey: "webexCountry")
static var webexISO: String?
get return self.defaults.string(forKey: "webexISO")
set self.defaults.set(newValue, forKey: "webexISO")
//Webex participant code, this is stored as the participant code is required to dial in even when the user is hosting.
static var webexAccessCode: String?
get return self.defaults.string(forKey: "webexAccessCode")
set self.defaults.set(newValue, forKey: "webexAccessCode")
static var webexHostPin: String?
get return self.defaults.string(forKey: "webexHostPin")
set self.defaults.set(newValue, forKey: "webexHostPin")
///ZOOM
static var zoomNumber: String?
get return self.defaults.string(forKey: "zoomNumber")
set self.defaults.set(newValue, forKey: "zoomNumber")
static var zoomCountry: String?
get return self.defaults.string(forKey: "zoomCountry")
set self.defaults.set(newValue, forKey: "zoomCountry")
static var zoomISO: String?
get return self.defaults.string(forKey: "zoomISO")
set self.defaults.set(newValue, forKey: "zoomISO")
static var zoomMeetingId: String?
get return self.defaults.string(forKey: "zoomMeetingId")
set self.defaults.set(newValue, forKey: "zoomMeetingId")
// MARK: User
///Country
static var country: String?
get return self.defaults.string(forKey: "country")
set self.defaults.set(newValue, forKey: "country")
static var email: String?
get return self.defaults.string(forKey: "email")
set self.defaults.set(newValue, forKey: "email")
///Return the user's name. If this hasn't been saved extract their name from their arkadin calendar and save it.
static var usersName: String?
if let savedName = defaults.string(forKey: "name")
return savedName
if let calendar = MeetingsFetcher().getarkadinCalendar().first,
let parsedName = calendar.title.parseFirstMatch(from: Regex.organizerNameFromEKCalendar)
defaults.set(parsedName, forKey: "name")
return parsedName
return AppConfigInteractor.getUserName()
static var callMethod: String
get
if let method = self.defaults.string(forKey: "callMethod")
return method
else
return CallMethod.methods.device.rawValue
set self.defaults.set(newValue, forKey: "callMethod")
///VIPS: email + relation for a max of 9 VIPs
static var VIPemails: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPemails")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPemails")
static var VIPnames: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPnames")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPnames")
static var VIPrelations: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPrelations")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPrelations")
///notification
static var notificationsAllowed: Bool
get return self.defaults.bool(forKey: "notification")
set self.defaults.set(newValue, forKey: "notification")
///location awareness
static var locationAwarenessAllowed: Bool
get return self.defaults.bool(forKey: "locationAwareness")
set self.defaults.set(newValue, forKey: "locationAwareness")
///promt for authentication awareness
static var promptForAuthentication: Bool
get return self.defaults.bool(forKey: "promptForAuthentication")
set self.defaults.set(newValue, forKey: "promptForAuthentication")
///last time the user was prompt for authentication
static var lastAuthenticationPromptDate: Date?
get return self.defaults.object(forKey: "lastAuthenticationPromptDate") as? Date
set self.defaults.set(newValue, forKey: "lastAuthenticationPromptDate")
///audiosummary
static var audioSummary: Bool
get return self.defaults.bool(forKey: "audioSummary")
set self.defaults.set(newValue, forKey: "audioSummary")
/// Local settings (not stored in the cloud)
static var notifyNumberOfMinutesBeforeEvent: Double
get return self.defaults.double(forKey: "notifyNumberOfMinutesBeforeEvent")
set self.defaults.set(newValue, forKey: "notifyNumberOfMinutesBeforeEvent")
static var landingPageWasReadToday: Bool
get return self.defaults.bool(forKey: "landingPageWasReadToday")
set self.defaults.set(newValue, forKey: "landingPageWasReadToday")
static var lastDayAudioWasRead: Int
get return self.defaults.integer(forKey: "lastDayAudioWasRead")
set self.defaults.set(newValue, forKey: "lastDayAudioWasRead")
static var lastDayPopUpWasDismissed: Int
get return self.defaults.integer(forKey: "lastDayPopUpWasDismissed")
set self.defaults.set(newValue, forKey: "lastDayPopUpWasDismissed")
static var meetingsDismissed: [String]
get if let meetings = self.defaults.stringArray(forKey: "meetingsDismissed")
return meetings
else
return
set self.defaults.set(newValue, forKey: "meetingsDismissed")
static var promptToModifyNumber: Bool
get return self.defaults.bool(forKey: "promptToModifyNumber")
set self.defaults.set(newValue, forKey: "promptToModifyNumber")
///returns true if the user has already gone though the onboarding process
static var didOnboarding: Bool
get return self.defaults.bool(forKey: "didOnboarding")
set self.defaults.set(newValue, forKey: "didOnboarding")
static var advancedParticipantCode: String
get
if let code = self.defaults.string(forKey:"advancedParticipantCode")
return code
else
return SharedGlobals.Call.DEFAULT_PARTICIPANT_CODE
set self.defaults.set(newValue, forKey: "advancedParticipantCode")
static var advancedHostCode: String
get
if let code = self.defaults.string(forKey:"advancedHostCode")
return code
else
return SharedGlobals.Call.DEFAULT_HOST_CODE
set self.defaults.set(newValue, forKey: "advancedHostCode")
static var advancedNoCode: String
get
if let code = self.defaults.string(forKey: "advancedNoCode")
return code
else
return SharedGlobals.Call.DEFAULT_NO_CODE
set self.defaults.set(newValue, forKey: "advancedNoCode")
static var versionID: String?
get return self.defaults.string(forKey: "versionID")
set self.defaults.set(newValue, forKey: "versionID")
static var buildID: String?
get return self.defaults.string(forKey:"buildID")
set self.defaults.set(newValue, forKey: "buildID")
///always use conference number and ignore number in invitation
static var prioritizeSettingsNumbers: Bool
get return self.defaults.bool(forKey: "prioritizeSettingsNumbers")
set self.defaults.set(newValue, forKey: "prioritizeSettingsNumbers")
///Returns the settings number for a given provider or the AT&T number if provider is unknown.
static func phoneNumber(for provider: ConferenceProvider) -> String?
switch provider
case .unknown:
return attNumber ?? webexNumber ?? arkadinMeetingsNumber ?? zoomNumber
case .att:
return attNumber
case .arkadinMeetings:
return arkadinMeetingsNumber
case .webex:
return webexNumber
case .zoom:
return zoomNumber
///Returns the iso code for the current Settings number of a given provider, returns nil if no settings number is set.
static func isoCodeForSettingsNumber(with provider: ConferenceProvider) -> String?
switch provider
case .unknown:
return nil
case .att:
return attISO
case .arkadinMeetings:
return arkadinMeetingsISO
case .webex:
return webexISO
case .zoom:
return zoomISO
/**
Returns the participant codes for a given provider
- Note: Returns an empty array for arkadinMeetings as we don't store these participant codes.
- Note: For unknown providers this returns the participant codes for all meetings other than AT&T
as the user is unlikely to ever dial in with their own AT&T participant code (they'd use their host code).
*/
static func participantCodes(for provider: ConferenceProvider) -> [String]
switch provider
case .unknown:
return [webexAccessCode, zoomMeetingId].flatMap$0
case .att:
return attParticipantCodes
case .arkadinMeetings:
return
case .webex:
return [webexAccessCode].flatMap$0
case .zoom:
return [zoomMeetingId].flatMap$0
/**
Returns the host codes for a given provider
- Note: Returns an empty array for zoom conference calls as they have no host codes.
- Note: For unknown providers this returns all hostcodes
*/
static func hostCodes(for provider: ConferenceProvider) -> [String]
switch provider
case .unknown:
return attHostCodes + [arkadinMeetingsModeratorCode ,webexHostPin].flatMap$0
case .att:
return attHostCodes
case .arkadinMeetings:
return [arkadinMeetingsModeratorCode].flatMap$0
case .webex:
return [webexHostPin].flatMap$0
case .zoom:
return
object-oriented swift protocols
add a comment |Â
up vote
2
down vote
favorite
I'm developing an app that joins tele-conference calls so we use conference numbers a lot. I've got this basic structure to encapsulate the information regarding a conference number.
///A model that represents a teleconference number.
struct ConferenceNumber
let iso : String ///Interntational Standardised 2 letter Abbreviation for country.
let conferenceProvider: ConferenceProvider ///The company that hosts the conference call the number is for.
let number : String ///The phone number
let toll : Bool ///Whether the number is a paid or free line.
let country: String
init(ISO: String, country: String, number:String, provider: ConferenceProvider, toll: Bool)
self.iso = ISO
self.country = ConferenceNumber.localeName(from: ISO) ?? country
self.number = number
self.conferenceProvider = provider
self.toll = toll
I'm running in to two problems:
This class if often bypassed in favour of storing the numbers in
[String]arrays. I can't think of a nice way to put this in to an object asConferenceNumber.numberdoesn't sound right.The
conferenceProviderproperty has resulted in over a dozen switch statement in our code base which all look similar to the code below. Is it possible to reduce repeating myself this often with protocols or subclasses?
ConferenceProvider enum
///Defines the type of conference call service the meeting uses if any.
public enum ConferenceProvider : String
case unknown = "",
zoom = "Zoom",
att = "AT&T",
webex = "WebEx",
arkadin = "Arkadin"
Class with ConferenceProvider switch statements example
import Foundation
///Builds, stores, retrieves and queries conference number directories.
class ConferenceNumberDirectory
static let att: [ConferenceNumber] =
return buildDirectory(for: .att, from: jsonArray)
()
static let arkadinMeetings: [ConferenceNumber] =
return buildDirectory(for: .arkadinMeetings, from: jsonArray)
()
static let webex: [ConferenceNumber] =
return buildDirectory(for: .webex, from: jsonArray)
()
static let zoom: [ConferenceNumber] =
return buildDirectory(for: .zoom, from: jsonArray)
()
static let allProviders: [ConferenceNumber] =
return att + arkadinMeetings + webex + zoom
()
static let attPhoneNumbers: [String] =
return ConferenceNumberDirectory.att.map( $0.number )
()
static let arkadinMeetingsPhoneNumbers: [String] =
return ConferenceNumberDirectory.arkadinMeetings.map( $0.number )
()
static let webexPhoneNumbers: [String] =
return ConferenceNumberDirectory.webex.map( $0.number )
()
static let zoomPhoneNumbers: [String] =
return ConferenceNumberDirectory.zoom.map( $0.number )
()
static let allPhoneNumber: [String] =
return ConferenceNumberDirectory.allProviders.map $0.number
()
private static let jsonArray: [Any]? =
guard let numbersFilePath = Bundle.main.path(forResource: "numbers", ofType:"json") else
return nil
let data = try! Data(contentsOf: URL(fileURLWithPath:numbersFilePath), options: .uncached)
return try! JSONSerialization.jsonObject(with: data) as? [Any]
()
///Takes the outputted [Any]? from a JSON file and builds an Array of ConferenceNumber objects suitable for Call In to use.
static func buildDirectory(for conferenceProvider: ConferenceProvider, from jsonArray: [Any]?) -> [ConferenceNumber]
var directory = [ConferenceNumber]()
do
guard let rootJSONArray = jsonArray else
throw SerializationError.missing("JSON Root")
for entry in rootJSONArray
guard let dictionary = entry as? [String: Any] else
throw SerializationError.missing("JSON Root")
guard let isoCode = dictionary["ISO Code"] as? String else
throw SerializationError.missing("isoCode")
guard let country = dictionary["Country"] as? String else
throw SerializationError.missing("country")
if let key = getTollKey(for: conferenceProvider), let tollNumbers = try self.extractNumbers(from: dictionary, forKey: key)
directory.append(contentsOf: tollNumbers.mapConferenceNumber(ISO: isoCode, country: country, number: $0, provider: conferenceProvider, toll: true) )
if let key = getTollFreeKey(for: conferenceProvider), let tollFreeNumbers = try self.extractNumbers(from: dictionary, forKey: key)
directory.append(contentsOf: tollFreeNumbers.mapConferenceNumber(ISO: isoCode, country: country, number: $0, provider: conferenceProvider, toll: false))
catch let error
print(error)
return directory
///Returns the directory for a given conference provider. Returns all if no numbers exist for this provider.
static func getDirectory(for conferenceProvider: ConferenceProvider) -> [ConferenceNumber]?
switch conferenceProvider
case .arkadinMeetings:
return ConferenceNumberDirectory.arkadinMeetings
case .att:
return ConferenceNumberDirectory.att
case .webex:
return ConferenceNumberDirectory.webex
case .zoom:
return ConferenceNumberDirectory.zoom
default:
return ConferenceNumberDirectory.att + ConferenceNumberDirectory.arkadinMeetings + ConferenceNumberDirectory.webex + ConferenceNumberDirectory.zoom
/**
Returns a ConferenceNumber that matches the phone number and the country ISO code provided. Returns nil if no number is found.
- parameter number: The phone number to try and find a match for
- parameter isoCode: The international standard organizations 2 digit code that represents a country for all known languages
At present we do not store ConferenceNumber Objects in the settings so we often need to convert the Strings we store back in to their original conference number. Where we to save the object we would still need this as user entered numbers will not contain all ConferenceNumber properties.
*/
static func findConferenceNumber(usingNumber number: String, andISOCode isoCode: String?, fromDirectory conferenceProvider: ConferenceProvider = .unknown) -> ConferenceNumber?
if number.isEmpty
/**
Returns all conference numbers that share the same number.
Similarly as the previous one, findConferenceNumber() but getting all possibilities because we know that some countries share the same number, example: 8884266840
*/
static func findConferenceNumbers(usingNumber number: String, fromDirectory conferenceProvider: ConferenceProvider? = .unknown) -> [ConferenceNumber]
if number.isEmpty
return
switch conferenceProvider
case .att?:
return ConferenceNumberDirectory.att.filter( $0.number == number)
case .arkadinMeetings?:
return ConferenceNumberDirectory.arkadinMeetings.filter($0.number == number)
case .webex?:
return ConferenceNumberDirectory.webex.filter( $0.number == number)
case .zoom?:
return ConferenceNumberDirectory.zoom.filter($0.number == number)
default:
let allConferenceNumbers = ConferenceNumberDirectory.att + ConferenceNumberDirectory.arkadinMeetings + ConferenceNumberDirectory.webex + ConferenceNumberDirectory.zoom
return allConferenceNumbers.filter($0.number == number)
///Find the provider for a given number, return unknown if the number does not exist
///- warning: This will return the first provider that has the current number seeing as providers don't share numbers.
static func findProvider(forNumber queriedNumber: String) -> ConferenceProvider
return ConferenceNumberDirectory.allProviders.first $0.number == queriedNumber ?.conferenceProvider ?? .unknown
///Returns an array of all country iso codes a queriedNumber is used by.
static func findCountryISOCodes(forNumber queriedNumber: String) -> [String]
return ConferenceNumberDirectory.allProviders.filter $0.number == queriedNumber .map( $0.iso )
///Extracts telephone numbers from a given dictionary and key by taking the value as a string then returning an array of each comma seperated component of that string.
private static func extractNumbers(from dictionary: [String: Any], forKey key: String?) throws -> [String]?
guard let jsonKey = key ,let tollNumbersString = dictionary[jsonKey] as? String else
throw SerializationError.missing(key ?? "key is nil")
if tollNumbersString.isEmpty
return nil
return tollNumbersString.components(separatedBy: ",")
///Returns the JSON key to access a given ConferenceProviders toll numbers.
private static func getTollKey(for provider: ConferenceProvider) -> String?
switch provider
case .att:
return "AT&T toll"
case .arkadinMeetings:
return "arkadin Meetings toll"
case .webex:
return "Webex toll"
case .zoom:
return "Zoom toll"
default:
return nil
///Returns the JSON key to access a given ConferenceProviders toll-free numbers.
private static func getTollFreeKey(for provider: ConferenceProvider) -> String?
switch provider
case .att:
return "AT&T toll-free"
case .arkadinMeetings:
return "arkadin Meetings toll-free"
case .webex:
return "Webex toll-free"
default:
return nil
Class with ConferenceProvider switch statements Example 2
/// Data class, responsible for storing and retrieving of user settings.
import Foundation
class Settings
/// init user defaults with the app group suite to be able to use the same values in the app and in the widget
static let defaults = SharedGlobals.appGroupDefaults
static var id: String?
get return self.defaults.string(forKey: "id")
set self.defaults.set(newValue, forKey: "id")
static var attNumber: String?
get return self.defaults.string(forKey: "attNumber")
set self.defaults.set(newValue, forKey: "attNumber")
static var attCountry: String?
get return self.defaults.string(forKey: "attCountry")
set self.defaults.set(newValue, forKey: "attCountry")
static var attISO: String?
get return self.defaults.string(forKey: "attISO")
set self.defaults.set(newValue, forKey: "attISO")
static var attHostCodes: [String]
get if let codes = self.defaults.stringArray(forKey: "hostCodes")
return codes
else
return
set self.defaults.set(newValue, forKey: "hostCodes")
///AT&T participant codes, these are paired to hostcodes (by index) so we can determine which host code to use via parsed participant codes.
static var attParticipantCodes: [String]
get if let codes = self.defaults.stringArray(forKey: "participantCodes")
return codes
else
return
set self.defaults.set(newValue, forKey: "participantCodes")
///arkadinMeetings (Smartcloud)
static var arkadinMeetingsCountry: String?
get return self.defaults.string(forKey: "arkadinMeetingsCountry")
set self.defaults.set(newValue, forKey: "arkadinMeetingsCountry")
static var arkadinMeetingsNumber: String?
get return self.defaults.string(forKey: "arkadinMeetingsNumber")
set self.defaults.set(newValue, forKey: "arkadinMeetingsNumber")
static var arkadinMeetingsISO: String?
get return self.defaults.string(forKey: "arkadinMeetingsISO")
set self.defaults.set(newValue, forKey: "arkadinMeetingsISO")
static var arkadinMeetingsModeratorCode: String?
get return self.defaults.string(forKey: "arkadinMeetingsModeratorCode")
set self.defaults.set(newValue, forKey: "arkadinMeetingsModeratorCode")
///WEBEX
static var webexNumber: String?
get return self.defaults.string(forKey: "webexNumber")
set self.defaults.set(newValue, forKey: "webexNumber")
static var webexCountry: String?
get return self.defaults.string(forKey: "webexCountry")
set self.defaults.set(newValue, forKey: "webexCountry")
static var webexISO: String?
get return self.defaults.string(forKey: "webexISO")
set self.defaults.set(newValue, forKey: "webexISO")
//Webex participant code, this is stored as the participant code is required to dial in even when the user is hosting.
static var webexAccessCode: String?
get return self.defaults.string(forKey: "webexAccessCode")
set self.defaults.set(newValue, forKey: "webexAccessCode")
static var webexHostPin: String?
get return self.defaults.string(forKey: "webexHostPin")
set self.defaults.set(newValue, forKey: "webexHostPin")
///ZOOM
static var zoomNumber: String?
get return self.defaults.string(forKey: "zoomNumber")
set self.defaults.set(newValue, forKey: "zoomNumber")
static var zoomCountry: String?
get return self.defaults.string(forKey: "zoomCountry")
set self.defaults.set(newValue, forKey: "zoomCountry")
static var zoomISO: String?
get return self.defaults.string(forKey: "zoomISO")
set self.defaults.set(newValue, forKey: "zoomISO")
static var zoomMeetingId: String?
get return self.defaults.string(forKey: "zoomMeetingId")
set self.defaults.set(newValue, forKey: "zoomMeetingId")
// MARK: User
///Country
static var country: String?
get return self.defaults.string(forKey: "country")
set self.defaults.set(newValue, forKey: "country")
static var email: String?
get return self.defaults.string(forKey: "email")
set self.defaults.set(newValue, forKey: "email")
///Return the user's name. If this hasn't been saved extract their name from their arkadin calendar and save it.
static var usersName: String?
if let savedName = defaults.string(forKey: "name")
return savedName
if let calendar = MeetingsFetcher().getarkadinCalendar().first,
let parsedName = calendar.title.parseFirstMatch(from: Regex.organizerNameFromEKCalendar)
defaults.set(parsedName, forKey: "name")
return parsedName
return AppConfigInteractor.getUserName()
static var callMethod: String
get
if let method = self.defaults.string(forKey: "callMethod")
return method
else
return CallMethod.methods.device.rawValue
set self.defaults.set(newValue, forKey: "callMethod")
///VIPS: email + relation for a max of 9 VIPs
static var VIPemails: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPemails")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPemails")
static var VIPnames: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPnames")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPnames")
static var VIPrelations: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPrelations")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPrelations")
///notification
static var notificationsAllowed: Bool
get return self.defaults.bool(forKey: "notification")
set self.defaults.set(newValue, forKey: "notification")
///location awareness
static var locationAwarenessAllowed: Bool
get return self.defaults.bool(forKey: "locationAwareness")
set self.defaults.set(newValue, forKey: "locationAwareness")
///promt for authentication awareness
static var promptForAuthentication: Bool
get return self.defaults.bool(forKey: "promptForAuthentication")
set self.defaults.set(newValue, forKey: "promptForAuthentication")
///last time the user was prompt for authentication
static var lastAuthenticationPromptDate: Date?
get return self.defaults.object(forKey: "lastAuthenticationPromptDate") as? Date
set self.defaults.set(newValue, forKey: "lastAuthenticationPromptDate")
///audiosummary
static var audioSummary: Bool
get return self.defaults.bool(forKey: "audioSummary")
set self.defaults.set(newValue, forKey: "audioSummary")
/// Local settings (not stored in the cloud)
static var notifyNumberOfMinutesBeforeEvent: Double
get return self.defaults.double(forKey: "notifyNumberOfMinutesBeforeEvent")
set self.defaults.set(newValue, forKey: "notifyNumberOfMinutesBeforeEvent")
static var landingPageWasReadToday: Bool
get return self.defaults.bool(forKey: "landingPageWasReadToday")
set self.defaults.set(newValue, forKey: "landingPageWasReadToday")
static var lastDayAudioWasRead: Int
get return self.defaults.integer(forKey: "lastDayAudioWasRead")
set self.defaults.set(newValue, forKey: "lastDayAudioWasRead")
static var lastDayPopUpWasDismissed: Int
get return self.defaults.integer(forKey: "lastDayPopUpWasDismissed")
set self.defaults.set(newValue, forKey: "lastDayPopUpWasDismissed")
static var meetingsDismissed: [String]
get if let meetings = self.defaults.stringArray(forKey: "meetingsDismissed")
return meetings
else
return
set self.defaults.set(newValue, forKey: "meetingsDismissed")
static var promptToModifyNumber: Bool
get return self.defaults.bool(forKey: "promptToModifyNumber")
set self.defaults.set(newValue, forKey: "promptToModifyNumber")
///returns true if the user has already gone though the onboarding process
static var didOnboarding: Bool
get return self.defaults.bool(forKey: "didOnboarding")
set self.defaults.set(newValue, forKey: "didOnboarding")
static var advancedParticipantCode: String
get
if let code = self.defaults.string(forKey:"advancedParticipantCode")
return code
else
return SharedGlobals.Call.DEFAULT_PARTICIPANT_CODE
set self.defaults.set(newValue, forKey: "advancedParticipantCode")
static var advancedHostCode: String
get
if let code = self.defaults.string(forKey:"advancedHostCode")
return code
else
return SharedGlobals.Call.DEFAULT_HOST_CODE
set self.defaults.set(newValue, forKey: "advancedHostCode")
static var advancedNoCode: String
get
if let code = self.defaults.string(forKey: "advancedNoCode")
return code
else
return SharedGlobals.Call.DEFAULT_NO_CODE
set self.defaults.set(newValue, forKey: "advancedNoCode")
static var versionID: String?
get return self.defaults.string(forKey: "versionID")
set self.defaults.set(newValue, forKey: "versionID")
static var buildID: String?
get return self.defaults.string(forKey:"buildID")
set self.defaults.set(newValue, forKey: "buildID")
///always use conference number and ignore number in invitation
static var prioritizeSettingsNumbers: Bool
get return self.defaults.bool(forKey: "prioritizeSettingsNumbers")
set self.defaults.set(newValue, forKey: "prioritizeSettingsNumbers")
///Returns the settings number for a given provider or the AT&T number if provider is unknown.
static func phoneNumber(for provider: ConferenceProvider) -> String?
switch provider
case .unknown:
return attNumber ?? webexNumber ?? arkadinMeetingsNumber ?? zoomNumber
case .att:
return attNumber
case .arkadinMeetings:
return arkadinMeetingsNumber
case .webex:
return webexNumber
case .zoom:
return zoomNumber
///Returns the iso code for the current Settings number of a given provider, returns nil if no settings number is set.
static func isoCodeForSettingsNumber(with provider: ConferenceProvider) -> String?
switch provider
case .unknown:
return nil
case .att:
return attISO
case .arkadinMeetings:
return arkadinMeetingsISO
case .webex:
return webexISO
case .zoom:
return zoomISO
/**
Returns the participant codes for a given provider
- Note: Returns an empty array for arkadinMeetings as we don't store these participant codes.
- Note: For unknown providers this returns the participant codes for all meetings other than AT&T
as the user is unlikely to ever dial in with their own AT&T participant code (they'd use their host code).
*/
static func participantCodes(for provider: ConferenceProvider) -> [String]
switch provider
case .unknown:
return [webexAccessCode, zoomMeetingId].flatMap$0
case .att:
return attParticipantCodes
case .arkadinMeetings:
return
case .webex:
return [webexAccessCode].flatMap$0
case .zoom:
return [zoomMeetingId].flatMap$0
/**
Returns the host codes for a given provider
- Note: Returns an empty array for zoom conference calls as they have no host codes.
- Note: For unknown providers this returns all hostcodes
*/
static func hostCodes(for provider: ConferenceProvider) -> [String]
switch provider
case .unknown:
return attHostCodes + [arkadinMeetingsModeratorCode ,webexHostPin].flatMap$0
case .att:
return attHostCodes
case .arkadinMeetings:
return [arkadinMeetingsModeratorCode].flatMap$0
case .webex:
return [webexHostPin].flatMap$0
case .zoom:
return
object-oriented swift protocols
What is the significance of knowing the provider? Why would a user care if AT&T provider the conferencing vs. IBM?
â user1118321
Mar 4 at 21:34
@user1118321 We store phone numbers for these different providers which we will want to put in to the meeting if we detect text or URLs specific to that provider. The user can also store settings for each providers where they can select or put their own number in as well as add participant codes/ host codes for that number. Different providers also use different dial codes.
â Deco
Mar 5 at 14:38
1
let number : String ///The phone numberImagine if you just named the variablelet phoneNumber: String. You wouldn't need a comment. Same withtoll->isTollFree(although that has the inverted meaning)
â Alexander
Mar 21 at 18:09
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
I'm developing an app that joins tele-conference calls so we use conference numbers a lot. I've got this basic structure to encapsulate the information regarding a conference number.
///A model that represents a teleconference number.
struct ConferenceNumber
let iso : String ///Interntational Standardised 2 letter Abbreviation for country.
let conferenceProvider: ConferenceProvider ///The company that hosts the conference call the number is for.
let number : String ///The phone number
let toll : Bool ///Whether the number is a paid or free line.
let country: String
init(ISO: String, country: String, number:String, provider: ConferenceProvider, toll: Bool)
self.iso = ISO
self.country = ConferenceNumber.localeName(from: ISO) ?? country
self.number = number
self.conferenceProvider = provider
self.toll = toll
I'm running in to two problems:
This class if often bypassed in favour of storing the numbers in
[String]arrays. I can't think of a nice way to put this in to an object asConferenceNumber.numberdoesn't sound right.The
conferenceProviderproperty has resulted in over a dozen switch statement in our code base which all look similar to the code below. Is it possible to reduce repeating myself this often with protocols or subclasses?
ConferenceProvider enum
///Defines the type of conference call service the meeting uses if any.
public enum ConferenceProvider : String
case unknown = "",
zoom = "Zoom",
att = "AT&T",
webex = "WebEx",
arkadin = "Arkadin"
Class with ConferenceProvider switch statements example
import Foundation
///Builds, stores, retrieves and queries conference number directories.
class ConferenceNumberDirectory
static let att: [ConferenceNumber] =
return buildDirectory(for: .att, from: jsonArray)
()
static let arkadinMeetings: [ConferenceNumber] =
return buildDirectory(for: .arkadinMeetings, from: jsonArray)
()
static let webex: [ConferenceNumber] =
return buildDirectory(for: .webex, from: jsonArray)
()
static let zoom: [ConferenceNumber] =
return buildDirectory(for: .zoom, from: jsonArray)
()
static let allProviders: [ConferenceNumber] =
return att + arkadinMeetings + webex + zoom
()
static let attPhoneNumbers: [String] =
return ConferenceNumberDirectory.att.map( $0.number )
()
static let arkadinMeetingsPhoneNumbers: [String] =
return ConferenceNumberDirectory.arkadinMeetings.map( $0.number )
()
static let webexPhoneNumbers: [String] =
return ConferenceNumberDirectory.webex.map( $0.number )
()
static let zoomPhoneNumbers: [String] =
return ConferenceNumberDirectory.zoom.map( $0.number )
()
static let allPhoneNumber: [String] =
return ConferenceNumberDirectory.allProviders.map $0.number
()
private static let jsonArray: [Any]? =
guard let numbersFilePath = Bundle.main.path(forResource: "numbers", ofType:"json") else
return nil
let data = try! Data(contentsOf: URL(fileURLWithPath:numbersFilePath), options: .uncached)
return try! JSONSerialization.jsonObject(with: data) as? [Any]
()
///Takes the outputted [Any]? from a JSON file and builds an Array of ConferenceNumber objects suitable for Call In to use.
static func buildDirectory(for conferenceProvider: ConferenceProvider, from jsonArray: [Any]?) -> [ConferenceNumber]
var directory = [ConferenceNumber]()
do
guard let rootJSONArray = jsonArray else
throw SerializationError.missing("JSON Root")
for entry in rootJSONArray
guard let dictionary = entry as? [String: Any] else
throw SerializationError.missing("JSON Root")
guard let isoCode = dictionary["ISO Code"] as? String else
throw SerializationError.missing("isoCode")
guard let country = dictionary["Country"] as? String else
throw SerializationError.missing("country")
if let key = getTollKey(for: conferenceProvider), let tollNumbers = try self.extractNumbers(from: dictionary, forKey: key)
directory.append(contentsOf: tollNumbers.mapConferenceNumber(ISO: isoCode, country: country, number: $0, provider: conferenceProvider, toll: true) )
if let key = getTollFreeKey(for: conferenceProvider), let tollFreeNumbers = try self.extractNumbers(from: dictionary, forKey: key)
directory.append(contentsOf: tollFreeNumbers.mapConferenceNumber(ISO: isoCode, country: country, number: $0, provider: conferenceProvider, toll: false))
catch let error
print(error)
return directory
///Returns the directory for a given conference provider. Returns all if no numbers exist for this provider.
static func getDirectory(for conferenceProvider: ConferenceProvider) -> [ConferenceNumber]?
switch conferenceProvider
case .arkadinMeetings:
return ConferenceNumberDirectory.arkadinMeetings
case .att:
return ConferenceNumberDirectory.att
case .webex:
return ConferenceNumberDirectory.webex
case .zoom:
return ConferenceNumberDirectory.zoom
default:
return ConferenceNumberDirectory.att + ConferenceNumberDirectory.arkadinMeetings + ConferenceNumberDirectory.webex + ConferenceNumberDirectory.zoom
/**
Returns a ConferenceNumber that matches the phone number and the country ISO code provided. Returns nil if no number is found.
- parameter number: The phone number to try and find a match for
- parameter isoCode: The international standard organizations 2 digit code that represents a country for all known languages
At present we do not store ConferenceNumber Objects in the settings so we often need to convert the Strings we store back in to their original conference number. Where we to save the object we would still need this as user entered numbers will not contain all ConferenceNumber properties.
*/
static func findConferenceNumber(usingNumber number: String, andISOCode isoCode: String?, fromDirectory conferenceProvider: ConferenceProvider = .unknown) -> ConferenceNumber?
if number.isEmpty
/**
Returns all conference numbers that share the same number.
Similarly as the previous one, findConferenceNumber() but getting all possibilities because we know that some countries share the same number, example: 8884266840
*/
static func findConferenceNumbers(usingNumber number: String, fromDirectory conferenceProvider: ConferenceProvider? = .unknown) -> [ConferenceNumber]
if number.isEmpty
return
switch conferenceProvider
case .att?:
return ConferenceNumberDirectory.att.filter( $0.number == number)
case .arkadinMeetings?:
return ConferenceNumberDirectory.arkadinMeetings.filter($0.number == number)
case .webex?:
return ConferenceNumberDirectory.webex.filter( $0.number == number)
case .zoom?:
return ConferenceNumberDirectory.zoom.filter($0.number == number)
default:
let allConferenceNumbers = ConferenceNumberDirectory.att + ConferenceNumberDirectory.arkadinMeetings + ConferenceNumberDirectory.webex + ConferenceNumberDirectory.zoom
return allConferenceNumbers.filter($0.number == number)
///Find the provider for a given number, return unknown if the number does not exist
///- warning: This will return the first provider that has the current number seeing as providers don't share numbers.
static func findProvider(forNumber queriedNumber: String) -> ConferenceProvider
return ConferenceNumberDirectory.allProviders.first $0.number == queriedNumber ?.conferenceProvider ?? .unknown
///Returns an array of all country iso codes a queriedNumber is used by.
static func findCountryISOCodes(forNumber queriedNumber: String) -> [String]
return ConferenceNumberDirectory.allProviders.filter $0.number == queriedNumber .map( $0.iso )
///Extracts telephone numbers from a given dictionary and key by taking the value as a string then returning an array of each comma seperated component of that string.
private static func extractNumbers(from dictionary: [String: Any], forKey key: String?) throws -> [String]?
guard let jsonKey = key ,let tollNumbersString = dictionary[jsonKey] as? String else
throw SerializationError.missing(key ?? "key is nil")
if tollNumbersString.isEmpty
return nil
return tollNumbersString.components(separatedBy: ",")
///Returns the JSON key to access a given ConferenceProviders toll numbers.
private static func getTollKey(for provider: ConferenceProvider) -> String?
switch provider
case .att:
return "AT&T toll"
case .arkadinMeetings:
return "arkadin Meetings toll"
case .webex:
return "Webex toll"
case .zoom:
return "Zoom toll"
default:
return nil
///Returns the JSON key to access a given ConferenceProviders toll-free numbers.
private static func getTollFreeKey(for provider: ConferenceProvider) -> String?
switch provider
case .att:
return "AT&T toll-free"
case .arkadinMeetings:
return "arkadin Meetings toll-free"
case .webex:
return "Webex toll-free"
default:
return nil
Class with ConferenceProvider switch statements Example 2
/// Data class, responsible for storing and retrieving of user settings.
import Foundation
class Settings
/// init user defaults with the app group suite to be able to use the same values in the app and in the widget
static let defaults = SharedGlobals.appGroupDefaults
static var id: String?
get return self.defaults.string(forKey: "id")
set self.defaults.set(newValue, forKey: "id")
static var attNumber: String?
get return self.defaults.string(forKey: "attNumber")
set self.defaults.set(newValue, forKey: "attNumber")
static var attCountry: String?
get return self.defaults.string(forKey: "attCountry")
set self.defaults.set(newValue, forKey: "attCountry")
static var attISO: String?
get return self.defaults.string(forKey: "attISO")
set self.defaults.set(newValue, forKey: "attISO")
static var attHostCodes: [String]
get if let codes = self.defaults.stringArray(forKey: "hostCodes")
return codes
else
return
set self.defaults.set(newValue, forKey: "hostCodes")
///AT&T participant codes, these are paired to hostcodes (by index) so we can determine which host code to use via parsed participant codes.
static var attParticipantCodes: [String]
get if let codes = self.defaults.stringArray(forKey: "participantCodes")
return codes
else
return
set self.defaults.set(newValue, forKey: "participantCodes")
///arkadinMeetings (Smartcloud)
static var arkadinMeetingsCountry: String?
get return self.defaults.string(forKey: "arkadinMeetingsCountry")
set self.defaults.set(newValue, forKey: "arkadinMeetingsCountry")
static var arkadinMeetingsNumber: String?
get return self.defaults.string(forKey: "arkadinMeetingsNumber")
set self.defaults.set(newValue, forKey: "arkadinMeetingsNumber")
static var arkadinMeetingsISO: String?
get return self.defaults.string(forKey: "arkadinMeetingsISO")
set self.defaults.set(newValue, forKey: "arkadinMeetingsISO")
static var arkadinMeetingsModeratorCode: String?
get return self.defaults.string(forKey: "arkadinMeetingsModeratorCode")
set self.defaults.set(newValue, forKey: "arkadinMeetingsModeratorCode")
///WEBEX
static var webexNumber: String?
get return self.defaults.string(forKey: "webexNumber")
set self.defaults.set(newValue, forKey: "webexNumber")
static var webexCountry: String?
get return self.defaults.string(forKey: "webexCountry")
set self.defaults.set(newValue, forKey: "webexCountry")
static var webexISO: String?
get return self.defaults.string(forKey: "webexISO")
set self.defaults.set(newValue, forKey: "webexISO")
//Webex participant code, this is stored as the participant code is required to dial in even when the user is hosting.
static var webexAccessCode: String?
get return self.defaults.string(forKey: "webexAccessCode")
set self.defaults.set(newValue, forKey: "webexAccessCode")
static var webexHostPin: String?
get return self.defaults.string(forKey: "webexHostPin")
set self.defaults.set(newValue, forKey: "webexHostPin")
///ZOOM
static var zoomNumber: String?
get return self.defaults.string(forKey: "zoomNumber")
set self.defaults.set(newValue, forKey: "zoomNumber")
static var zoomCountry: String?
get return self.defaults.string(forKey: "zoomCountry")
set self.defaults.set(newValue, forKey: "zoomCountry")
static var zoomISO: String?
get return self.defaults.string(forKey: "zoomISO")
set self.defaults.set(newValue, forKey: "zoomISO")
static var zoomMeetingId: String?
get return self.defaults.string(forKey: "zoomMeetingId")
set self.defaults.set(newValue, forKey: "zoomMeetingId")
// MARK: User
///Country
static var country: String?
get return self.defaults.string(forKey: "country")
set self.defaults.set(newValue, forKey: "country")
static var email: String?
get return self.defaults.string(forKey: "email")
set self.defaults.set(newValue, forKey: "email")
///Return the user's name. If this hasn't been saved extract their name from their arkadin calendar and save it.
static var usersName: String?
if let savedName = defaults.string(forKey: "name")
return savedName
if let calendar = MeetingsFetcher().getarkadinCalendar().first,
let parsedName = calendar.title.parseFirstMatch(from: Regex.organizerNameFromEKCalendar)
defaults.set(parsedName, forKey: "name")
return parsedName
return AppConfigInteractor.getUserName()
static var callMethod: String
get
if let method = self.defaults.string(forKey: "callMethod")
return method
else
return CallMethod.methods.device.rawValue
set self.defaults.set(newValue, forKey: "callMethod")
///VIPS: email + relation for a max of 9 VIPs
static var VIPemails: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPemails")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPemails")
static var VIPnames: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPnames")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPnames")
static var VIPrelations: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPrelations")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPrelations")
///notification
static var notificationsAllowed: Bool
get return self.defaults.bool(forKey: "notification")
set self.defaults.set(newValue, forKey: "notification")
///location awareness
static var locationAwarenessAllowed: Bool
get return self.defaults.bool(forKey: "locationAwareness")
set self.defaults.set(newValue, forKey: "locationAwareness")
///promt for authentication awareness
static var promptForAuthentication: Bool
get return self.defaults.bool(forKey: "promptForAuthentication")
set self.defaults.set(newValue, forKey: "promptForAuthentication")
///last time the user was prompt for authentication
static var lastAuthenticationPromptDate: Date?
get return self.defaults.object(forKey: "lastAuthenticationPromptDate") as? Date
set self.defaults.set(newValue, forKey: "lastAuthenticationPromptDate")
///audiosummary
static var audioSummary: Bool
get return self.defaults.bool(forKey: "audioSummary")
set self.defaults.set(newValue, forKey: "audioSummary")
/// Local settings (not stored in the cloud)
static var notifyNumberOfMinutesBeforeEvent: Double
get return self.defaults.double(forKey: "notifyNumberOfMinutesBeforeEvent")
set self.defaults.set(newValue, forKey: "notifyNumberOfMinutesBeforeEvent")
static var landingPageWasReadToday: Bool
get return self.defaults.bool(forKey: "landingPageWasReadToday")
set self.defaults.set(newValue, forKey: "landingPageWasReadToday")
static var lastDayAudioWasRead: Int
get return self.defaults.integer(forKey: "lastDayAudioWasRead")
set self.defaults.set(newValue, forKey: "lastDayAudioWasRead")
static var lastDayPopUpWasDismissed: Int
get return self.defaults.integer(forKey: "lastDayPopUpWasDismissed")
set self.defaults.set(newValue, forKey: "lastDayPopUpWasDismissed")
static var meetingsDismissed: [String]
get if let meetings = self.defaults.stringArray(forKey: "meetingsDismissed")
return meetings
else
return
set self.defaults.set(newValue, forKey: "meetingsDismissed")
static var promptToModifyNumber: Bool
get return self.defaults.bool(forKey: "promptToModifyNumber")
set self.defaults.set(newValue, forKey: "promptToModifyNumber")
///returns true if the user has already gone though the onboarding process
static var didOnboarding: Bool
get return self.defaults.bool(forKey: "didOnboarding")
set self.defaults.set(newValue, forKey: "didOnboarding")
static var advancedParticipantCode: String
get
if let code = self.defaults.string(forKey:"advancedParticipantCode")
return code
else
return SharedGlobals.Call.DEFAULT_PARTICIPANT_CODE
set self.defaults.set(newValue, forKey: "advancedParticipantCode")
static var advancedHostCode: String
get
if let code = self.defaults.string(forKey:"advancedHostCode")
return code
else
return SharedGlobals.Call.DEFAULT_HOST_CODE
set self.defaults.set(newValue, forKey: "advancedHostCode")
static var advancedNoCode: String
get
if let code = self.defaults.string(forKey: "advancedNoCode")
return code
else
return SharedGlobals.Call.DEFAULT_NO_CODE
set self.defaults.set(newValue, forKey: "advancedNoCode")
static var versionID: String?
get return self.defaults.string(forKey: "versionID")
set self.defaults.set(newValue, forKey: "versionID")
static var buildID: String?
get return self.defaults.string(forKey:"buildID")
set self.defaults.set(newValue, forKey: "buildID")
///always use conference number and ignore number in invitation
static var prioritizeSettingsNumbers: Bool
get return self.defaults.bool(forKey: "prioritizeSettingsNumbers")
set self.defaults.set(newValue, forKey: "prioritizeSettingsNumbers")
///Returns the settings number for a given provider or the AT&T number if provider is unknown.
static func phoneNumber(for provider: ConferenceProvider) -> String?
switch provider
case .unknown:
return attNumber ?? webexNumber ?? arkadinMeetingsNumber ?? zoomNumber
case .att:
return attNumber
case .arkadinMeetings:
return arkadinMeetingsNumber
case .webex:
return webexNumber
case .zoom:
return zoomNumber
///Returns the iso code for the current Settings number of a given provider, returns nil if no settings number is set.
static func isoCodeForSettingsNumber(with provider: ConferenceProvider) -> String?
switch provider
case .unknown:
return nil
case .att:
return attISO
case .arkadinMeetings:
return arkadinMeetingsISO
case .webex:
return webexISO
case .zoom:
return zoomISO
/**
Returns the participant codes for a given provider
- Note: Returns an empty array for arkadinMeetings as we don't store these participant codes.
- Note: For unknown providers this returns the participant codes for all meetings other than AT&T
as the user is unlikely to ever dial in with their own AT&T participant code (they'd use their host code).
*/
static func participantCodes(for provider: ConferenceProvider) -> [String]
switch provider
case .unknown:
return [webexAccessCode, zoomMeetingId].flatMap$0
case .att:
return attParticipantCodes
case .arkadinMeetings:
return
case .webex:
return [webexAccessCode].flatMap$0
case .zoom:
return [zoomMeetingId].flatMap$0
/**
Returns the host codes for a given provider
- Note: Returns an empty array for zoom conference calls as they have no host codes.
- Note: For unknown providers this returns all hostcodes
*/
static func hostCodes(for provider: ConferenceProvider) -> [String]
switch provider
case .unknown:
return attHostCodes + [arkadinMeetingsModeratorCode ,webexHostPin].flatMap$0
case .att:
return attHostCodes
case .arkadinMeetings:
return [arkadinMeetingsModeratorCode].flatMap$0
case .webex:
return [webexHostPin].flatMap$0
case .zoom:
return
object-oriented swift protocols
I'm developing an app that joins tele-conference calls so we use conference numbers a lot. I've got this basic structure to encapsulate the information regarding a conference number.
///A model that represents a teleconference number.
struct ConferenceNumber
let iso : String ///Interntational Standardised 2 letter Abbreviation for country.
let conferenceProvider: ConferenceProvider ///The company that hosts the conference call the number is for.
let number : String ///The phone number
let toll : Bool ///Whether the number is a paid or free line.
let country: String
init(ISO: String, country: String, number:String, provider: ConferenceProvider, toll: Bool)
self.iso = ISO
self.country = ConferenceNumber.localeName(from: ISO) ?? country
self.number = number
self.conferenceProvider = provider
self.toll = toll
I'm running in to two problems:
This class if often bypassed in favour of storing the numbers in
[String]arrays. I can't think of a nice way to put this in to an object asConferenceNumber.numberdoesn't sound right.The
conferenceProviderproperty has resulted in over a dozen switch statement in our code base which all look similar to the code below. Is it possible to reduce repeating myself this often with protocols or subclasses?
ConferenceProvider enum
///Defines the type of conference call service the meeting uses if any.
public enum ConferenceProvider : String
case unknown = "",
zoom = "Zoom",
att = "AT&T",
webex = "WebEx",
arkadin = "Arkadin"
Class with ConferenceProvider switch statements example
import Foundation
///Builds, stores, retrieves and queries conference number directories.
class ConferenceNumberDirectory
static let att: [ConferenceNumber] =
return buildDirectory(for: .att, from: jsonArray)
()
static let arkadinMeetings: [ConferenceNumber] =
return buildDirectory(for: .arkadinMeetings, from: jsonArray)
()
static let webex: [ConferenceNumber] =
return buildDirectory(for: .webex, from: jsonArray)
()
static let zoom: [ConferenceNumber] =
return buildDirectory(for: .zoom, from: jsonArray)
()
static let allProviders: [ConferenceNumber] =
return att + arkadinMeetings + webex + zoom
()
static let attPhoneNumbers: [String] =
return ConferenceNumberDirectory.att.map( $0.number )
()
static let arkadinMeetingsPhoneNumbers: [String] =
return ConferenceNumberDirectory.arkadinMeetings.map( $0.number )
()
static let webexPhoneNumbers: [String] =
return ConferenceNumberDirectory.webex.map( $0.number )
()
static let zoomPhoneNumbers: [String] =
return ConferenceNumberDirectory.zoom.map( $0.number )
()
static let allPhoneNumber: [String] =
return ConferenceNumberDirectory.allProviders.map $0.number
()
private static let jsonArray: [Any]? =
guard let numbersFilePath = Bundle.main.path(forResource: "numbers", ofType:"json") else
return nil
let data = try! Data(contentsOf: URL(fileURLWithPath:numbersFilePath), options: .uncached)
return try! JSONSerialization.jsonObject(with: data) as? [Any]
()
///Takes the outputted [Any]? from a JSON file and builds an Array of ConferenceNumber objects suitable for Call In to use.
static func buildDirectory(for conferenceProvider: ConferenceProvider, from jsonArray: [Any]?) -> [ConferenceNumber]
var directory = [ConferenceNumber]()
do
guard let rootJSONArray = jsonArray else
throw SerializationError.missing("JSON Root")
for entry in rootJSONArray
guard let dictionary = entry as? [String: Any] else
throw SerializationError.missing("JSON Root")
guard let isoCode = dictionary["ISO Code"] as? String else
throw SerializationError.missing("isoCode")
guard let country = dictionary["Country"] as? String else
throw SerializationError.missing("country")
if let key = getTollKey(for: conferenceProvider), let tollNumbers = try self.extractNumbers(from: dictionary, forKey: key)
directory.append(contentsOf: tollNumbers.mapConferenceNumber(ISO: isoCode, country: country, number: $0, provider: conferenceProvider, toll: true) )
if let key = getTollFreeKey(for: conferenceProvider), let tollFreeNumbers = try self.extractNumbers(from: dictionary, forKey: key)
directory.append(contentsOf: tollFreeNumbers.mapConferenceNumber(ISO: isoCode, country: country, number: $0, provider: conferenceProvider, toll: false))
catch let error
print(error)
return directory
///Returns the directory for a given conference provider. Returns all if no numbers exist for this provider.
static func getDirectory(for conferenceProvider: ConferenceProvider) -> [ConferenceNumber]?
switch conferenceProvider
case .arkadinMeetings:
return ConferenceNumberDirectory.arkadinMeetings
case .att:
return ConferenceNumberDirectory.att
case .webex:
return ConferenceNumberDirectory.webex
case .zoom:
return ConferenceNumberDirectory.zoom
default:
return ConferenceNumberDirectory.att + ConferenceNumberDirectory.arkadinMeetings + ConferenceNumberDirectory.webex + ConferenceNumberDirectory.zoom
/**
Returns a ConferenceNumber that matches the phone number and the country ISO code provided. Returns nil if no number is found.
- parameter number: The phone number to try and find a match for
- parameter isoCode: The international standard organizations 2 digit code that represents a country for all known languages
At present we do not store ConferenceNumber Objects in the settings so we often need to convert the Strings we store back in to their original conference number. Where we to save the object we would still need this as user entered numbers will not contain all ConferenceNumber properties.
*/
static func findConferenceNumber(usingNumber number: String, andISOCode isoCode: String?, fromDirectory conferenceProvider: ConferenceProvider = .unknown) -> ConferenceNumber?
if number.isEmpty
/**
Returns all conference numbers that share the same number.
Similarly as the previous one, findConferenceNumber() but getting all possibilities because we know that some countries share the same number, example: 8884266840
*/
static func findConferenceNumbers(usingNumber number: String, fromDirectory conferenceProvider: ConferenceProvider? = .unknown) -> [ConferenceNumber]
if number.isEmpty
return
switch conferenceProvider
case .att?:
return ConferenceNumberDirectory.att.filter( $0.number == number)
case .arkadinMeetings?:
return ConferenceNumberDirectory.arkadinMeetings.filter($0.number == number)
case .webex?:
return ConferenceNumberDirectory.webex.filter( $0.number == number)
case .zoom?:
return ConferenceNumberDirectory.zoom.filter($0.number == number)
default:
let allConferenceNumbers = ConferenceNumberDirectory.att + ConferenceNumberDirectory.arkadinMeetings + ConferenceNumberDirectory.webex + ConferenceNumberDirectory.zoom
return allConferenceNumbers.filter($0.number == number)
///Find the provider for a given number, return unknown if the number does not exist
///- warning: This will return the first provider that has the current number seeing as providers don't share numbers.
static func findProvider(forNumber queriedNumber: String) -> ConferenceProvider
return ConferenceNumberDirectory.allProviders.first $0.number == queriedNumber ?.conferenceProvider ?? .unknown
///Returns an array of all country iso codes a queriedNumber is used by.
static func findCountryISOCodes(forNumber queriedNumber: String) -> [String]
return ConferenceNumberDirectory.allProviders.filter $0.number == queriedNumber .map( $0.iso )
///Extracts telephone numbers from a given dictionary and key by taking the value as a string then returning an array of each comma seperated component of that string.
private static func extractNumbers(from dictionary: [String: Any], forKey key: String?) throws -> [String]?
guard let jsonKey = key ,let tollNumbersString = dictionary[jsonKey] as? String else
throw SerializationError.missing(key ?? "key is nil")
if tollNumbersString.isEmpty
return nil
return tollNumbersString.components(separatedBy: ",")
///Returns the JSON key to access a given ConferenceProviders toll numbers.
private static func getTollKey(for provider: ConferenceProvider) -> String?
switch provider
case .att:
return "AT&T toll"
case .arkadinMeetings:
return "arkadin Meetings toll"
case .webex:
return "Webex toll"
case .zoom:
return "Zoom toll"
default:
return nil
///Returns the JSON key to access a given ConferenceProviders toll-free numbers.
private static func getTollFreeKey(for provider: ConferenceProvider) -> String?
switch provider
case .att:
return "AT&T toll-free"
case .arkadinMeetings:
return "arkadin Meetings toll-free"
case .webex:
return "Webex toll-free"
default:
return nil
Class with ConferenceProvider switch statements Example 2
/// Data class, responsible for storing and retrieving of user settings.
import Foundation
class Settings
/// init user defaults with the app group suite to be able to use the same values in the app and in the widget
static let defaults = SharedGlobals.appGroupDefaults
static var id: String?
get return self.defaults.string(forKey: "id")
set self.defaults.set(newValue, forKey: "id")
static var attNumber: String?
get return self.defaults.string(forKey: "attNumber")
set self.defaults.set(newValue, forKey: "attNumber")
static var attCountry: String?
get return self.defaults.string(forKey: "attCountry")
set self.defaults.set(newValue, forKey: "attCountry")
static var attISO: String?
get return self.defaults.string(forKey: "attISO")
set self.defaults.set(newValue, forKey: "attISO")
static var attHostCodes: [String]
get if let codes = self.defaults.stringArray(forKey: "hostCodes")
return codes
else
return
set self.defaults.set(newValue, forKey: "hostCodes")
///AT&T participant codes, these are paired to hostcodes (by index) so we can determine which host code to use via parsed participant codes.
static var attParticipantCodes: [String]
get if let codes = self.defaults.stringArray(forKey: "participantCodes")
return codes
else
return
set self.defaults.set(newValue, forKey: "participantCodes")
///arkadinMeetings (Smartcloud)
static var arkadinMeetingsCountry: String?
get return self.defaults.string(forKey: "arkadinMeetingsCountry")
set self.defaults.set(newValue, forKey: "arkadinMeetingsCountry")
static var arkadinMeetingsNumber: String?
get return self.defaults.string(forKey: "arkadinMeetingsNumber")
set self.defaults.set(newValue, forKey: "arkadinMeetingsNumber")
static var arkadinMeetingsISO: String?
get return self.defaults.string(forKey: "arkadinMeetingsISO")
set self.defaults.set(newValue, forKey: "arkadinMeetingsISO")
static var arkadinMeetingsModeratorCode: String?
get return self.defaults.string(forKey: "arkadinMeetingsModeratorCode")
set self.defaults.set(newValue, forKey: "arkadinMeetingsModeratorCode")
///WEBEX
static var webexNumber: String?
get return self.defaults.string(forKey: "webexNumber")
set self.defaults.set(newValue, forKey: "webexNumber")
static var webexCountry: String?
get return self.defaults.string(forKey: "webexCountry")
set self.defaults.set(newValue, forKey: "webexCountry")
static var webexISO: String?
get return self.defaults.string(forKey: "webexISO")
set self.defaults.set(newValue, forKey: "webexISO")
//Webex participant code, this is stored as the participant code is required to dial in even when the user is hosting.
static var webexAccessCode: String?
get return self.defaults.string(forKey: "webexAccessCode")
set self.defaults.set(newValue, forKey: "webexAccessCode")
static var webexHostPin: String?
get return self.defaults.string(forKey: "webexHostPin")
set self.defaults.set(newValue, forKey: "webexHostPin")
///ZOOM
static var zoomNumber: String?
get return self.defaults.string(forKey: "zoomNumber")
set self.defaults.set(newValue, forKey: "zoomNumber")
static var zoomCountry: String?
get return self.defaults.string(forKey: "zoomCountry")
set self.defaults.set(newValue, forKey: "zoomCountry")
static var zoomISO: String?
get return self.defaults.string(forKey: "zoomISO")
set self.defaults.set(newValue, forKey: "zoomISO")
static var zoomMeetingId: String?
get return self.defaults.string(forKey: "zoomMeetingId")
set self.defaults.set(newValue, forKey: "zoomMeetingId")
// MARK: User
///Country
static var country: String?
get return self.defaults.string(forKey: "country")
set self.defaults.set(newValue, forKey: "country")
static var email: String?
get return self.defaults.string(forKey: "email")
set self.defaults.set(newValue, forKey: "email")
///Return the user's name. If this hasn't been saved extract their name from their arkadin calendar and save it.
static var usersName: String?
if let savedName = defaults.string(forKey: "name")
return savedName
if let calendar = MeetingsFetcher().getarkadinCalendar().first,
let parsedName = calendar.title.parseFirstMatch(from: Regex.organizerNameFromEKCalendar)
defaults.set(parsedName, forKey: "name")
return parsedName
return AppConfigInteractor.getUserName()
static var callMethod: String
get
if let method = self.defaults.string(forKey: "callMethod")
return method
else
return CallMethod.methods.device.rawValue
set self.defaults.set(newValue, forKey: "callMethod")
///VIPS: email + relation for a max of 9 VIPs
static var VIPemails: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPemails")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPemails")
static var VIPnames: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPnames")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPnames")
static var VIPrelations: [String]
get if let vips = self.defaults.stringArray(forKey: "VIPrelations")
return vips
else
return
set self.defaults.set(newValue, forKey: "VIPrelations")
///notification
static var notificationsAllowed: Bool
get return self.defaults.bool(forKey: "notification")
set self.defaults.set(newValue, forKey: "notification")
///location awareness
static var locationAwarenessAllowed: Bool
get return self.defaults.bool(forKey: "locationAwareness")
set self.defaults.set(newValue, forKey: "locationAwareness")
///promt for authentication awareness
static var promptForAuthentication: Bool
get return self.defaults.bool(forKey: "promptForAuthentication")
set self.defaults.set(newValue, forKey: "promptForAuthentication")
///last time the user was prompt for authentication
static var lastAuthenticationPromptDate: Date?
get return self.defaults.object(forKey: "lastAuthenticationPromptDate") as? Date
set self.defaults.set(newValue, forKey: "lastAuthenticationPromptDate")
///audiosummary
static var audioSummary: Bool
get return self.defaults.bool(forKey: "audioSummary")
set self.defaults.set(newValue, forKey: "audioSummary")
/// Local settings (not stored in the cloud)
static var notifyNumberOfMinutesBeforeEvent: Double
get return self.defaults.double(forKey: "notifyNumberOfMinutesBeforeEvent")
set self.defaults.set(newValue, forKey: "notifyNumberOfMinutesBeforeEvent")
static var landingPageWasReadToday: Bool
get return self.defaults.bool(forKey: "landingPageWasReadToday")
set self.defaults.set(newValue, forKey: "landingPageWasReadToday")
static var lastDayAudioWasRead: Int
get return self.defaults.integer(forKey: "lastDayAudioWasRead")
set self.defaults.set(newValue, forKey: "lastDayAudioWasRead")
static var lastDayPopUpWasDismissed: Int
get return self.defaults.integer(forKey: "lastDayPopUpWasDismissed")
set self.defaults.set(newValue, forKey: "lastDayPopUpWasDismissed")
static var meetingsDismissed: [String]
get if let meetings = self.defaults.stringArray(forKey: "meetingsDismissed")
return meetings
else
return
set self.defaults.set(newValue, forKey: "meetingsDismissed")
static var promptToModifyNumber: Bool
get return self.defaults.bool(forKey: "promptToModifyNumber")
set self.defaults.set(newValue, forKey: "promptToModifyNumber")
///returns true if the user has already gone though the onboarding process
static var didOnboarding: Bool
get return self.defaults.bool(forKey: "didOnboarding")
set self.defaults.set(newValue, forKey: "didOnboarding")
static var advancedParticipantCode: String
get
if let code = self.defaults.string(forKey:"advancedParticipantCode")
return code
else
return SharedGlobals.Call.DEFAULT_PARTICIPANT_CODE
set self.defaults.set(newValue, forKey: "advancedParticipantCode")
static var advancedHostCode: String
get
if let code = self.defaults.string(forKey:"advancedHostCode")
return code
else
return SharedGlobals.Call.DEFAULT_HOST_CODE
set self.defaults.set(newValue, forKey: "advancedHostCode")
static var advancedNoCode: String
get
if let code = self.defaults.string(forKey: "advancedNoCode")
return code
else
return SharedGlobals.Call.DEFAULT_NO_CODE
set self.defaults.set(newValue, forKey: "advancedNoCode")
static var versionID: String?
get return self.defaults.string(forKey: "versionID")
set self.defaults.set(newValue, forKey: "versionID")
static var buildID: String?
get return self.defaults.string(forKey:"buildID")
set self.defaults.set(newValue, forKey: "buildID")
///always use conference number and ignore number in invitation
static var prioritizeSettingsNumbers: Bool
get return self.defaults.bool(forKey: "prioritizeSettingsNumbers")
set self.defaults.set(newValue, forKey: "prioritizeSettingsNumbers")
///Returns the settings number for a given provider or the AT&T number if provider is unknown.
static func phoneNumber(for provider: ConferenceProvider) -> String?
switch provider
case .unknown:
return attNumber ?? webexNumber ?? arkadinMeetingsNumber ?? zoomNumber
case .att:
return attNumber
case .arkadinMeetings:
return arkadinMeetingsNumber
case .webex:
return webexNumber
case .zoom:
return zoomNumber
///Returns the iso code for the current Settings number of a given provider, returns nil if no settings number is set.
static func isoCodeForSettingsNumber(with provider: ConferenceProvider) -> String?
switch provider
case .unknown:
return nil
case .att:
return attISO
case .arkadinMeetings:
return arkadinMeetingsISO
case .webex:
return webexISO
case .zoom:
return zoomISO
/**
Returns the participant codes for a given provider
- Note: Returns an empty array for arkadinMeetings as we don't store these participant codes.
- Note: For unknown providers this returns the participant codes for all meetings other than AT&T
as the user is unlikely to ever dial in with their own AT&T participant code (they'd use their host code).
*/
static func participantCodes(for provider: ConferenceProvider) -> [String]
switch provider
case .unknown:
return [webexAccessCode, zoomMeetingId].flatMap$0
case .att:
return attParticipantCodes
case .arkadinMeetings:
return
case .webex:
return [webexAccessCode].flatMap$0
case .zoom:
return [zoomMeetingId].flatMap$0
/**
Returns the host codes for a given provider
- Note: Returns an empty array for zoom conference calls as they have no host codes.
- Note: For unknown providers this returns all hostcodes
*/
static func hostCodes(for provider: ConferenceProvider) -> [String]
switch provider
case .unknown:
return attHostCodes + [arkadinMeetingsModeratorCode ,webexHostPin].flatMap$0
case .att:
return attHostCodes
case .arkadinMeetings:
return [arkadinMeetingsModeratorCode].flatMap$0
case .webex:
return [webexHostPin].flatMap$0
case .zoom:
return
object-oriented swift protocols
edited Mar 5 at 14:35
asked Mar 3 at 21:55
Deco
11310
11310
What is the significance of knowing the provider? Why would a user care if AT&T provider the conferencing vs. IBM?
â user1118321
Mar 4 at 21:34
@user1118321 We store phone numbers for these different providers which we will want to put in to the meeting if we detect text or URLs specific to that provider. The user can also store settings for each providers where they can select or put their own number in as well as add participant codes/ host codes for that number. Different providers also use different dial codes.
â Deco
Mar 5 at 14:38
1
let number : String ///The phone numberImagine if you just named the variablelet phoneNumber: String. You wouldn't need a comment. Same withtoll->isTollFree(although that has the inverted meaning)
â Alexander
Mar 21 at 18:09
add a comment |Â
What is the significance of knowing the provider? Why would a user care if AT&T provider the conferencing vs. IBM?
â user1118321
Mar 4 at 21:34
@user1118321 We store phone numbers for these different providers which we will want to put in to the meeting if we detect text or URLs specific to that provider. The user can also store settings for each providers where they can select or put their own number in as well as add participant codes/ host codes for that number. Different providers also use different dial codes.
â Deco
Mar 5 at 14:38
1
let number : String ///The phone numberImagine if you just named the variablelet phoneNumber: String. You wouldn't need a comment. Same withtoll->isTollFree(although that has the inverted meaning)
â Alexander
Mar 21 at 18:09
What is the significance of knowing the provider? Why would a user care if AT&T provider the conferencing vs. IBM?
â user1118321
Mar 4 at 21:34
What is the significance of knowing the provider? Why would a user care if AT&T provider the conferencing vs. IBM?
â user1118321
Mar 4 at 21:34
@user1118321 We store phone numbers for these different providers which we will want to put in to the meeting if we detect text or URLs specific to that provider. The user can also store settings for each providers where they can select or put their own number in as well as add participant codes/ host codes for that number. Different providers also use different dial codes.
â Deco
Mar 5 at 14:38
@user1118321 We store phone numbers for these different providers which we will want to put in to the meeting if we detect text or URLs specific to that provider. The user can also store settings for each providers where they can select or put their own number in as well as add participant codes/ host codes for that number. Different providers also use different dial codes.
â Deco
Mar 5 at 14:38
1
1
let number : String ///The phone number Imagine if you just named the variable let phoneNumber: String. You wouldn't need a comment. Same with toll -> isTollFree (although that has the inverted meaning)â Alexander
Mar 21 at 18:09
let number : String ///The phone number Imagine if you just named the variable let phoneNumber: String. You wouldn't need a comment. Same with toll -> isTollFree (although that has the inverted meaning)â Alexander
Mar 21 at 18:09
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
0
down vote
accepted
I think you've used the wrong abstraction here. I think that's the cause of all these switch statements.
Use Objects or structs
One thing I notice is that it seems like a ConferenceProvider should be an object, not an enum. If it were an object you could hold the provider's name, a link to the ConferenceNumberDirectory entry for that provider, the toll key and the toll free key. Then most of your switch statements in the first example go away, and it just becomes extracting the information from the passed-in provider. It could look something like this:
struct ConferenceProvider
let providerName : String
let providerNumbers : [ConferenceNumber]
let tollKey : String
let tollFreeKey : String
init(providerName: String, providerNumbers: [ConferenceNumber], tollKey: String, tollFreeKey: String)
self.providerName = providerName
self.providerNumbers = providerNumbers
self.tollKey = tollKey
self.tollFreeKey = tollFreeKey
You'd then have to change getDirectory(for conferenceProvider: ) to do the lookup by name, or some other method. You'd probably want a Dictionary that mapped provider name to the above ConferenceProvider struct.
How would we apply this to something like number identification? At present we look for URLs and keywords then use something likemeeting.conferenceProvider = .attonce we identify the meeting uses AT&T teleconference calls.
â Deco
Mar 6 at 13:40
You would still have that information in the struct I mention above. It would just bemeeting.conferenceProvider.providerName. Or if you wanted it to still be anenumI suppose it could be anenuminstead of aString.
â user1118321
Mar 6 at 17:07
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
accepted
I think you've used the wrong abstraction here. I think that's the cause of all these switch statements.
Use Objects or structs
One thing I notice is that it seems like a ConferenceProvider should be an object, not an enum. If it were an object you could hold the provider's name, a link to the ConferenceNumberDirectory entry for that provider, the toll key and the toll free key. Then most of your switch statements in the first example go away, and it just becomes extracting the information from the passed-in provider. It could look something like this:
struct ConferenceProvider
let providerName : String
let providerNumbers : [ConferenceNumber]
let tollKey : String
let tollFreeKey : String
init(providerName: String, providerNumbers: [ConferenceNumber], tollKey: String, tollFreeKey: String)
self.providerName = providerName
self.providerNumbers = providerNumbers
self.tollKey = tollKey
self.tollFreeKey = tollFreeKey
You'd then have to change getDirectory(for conferenceProvider: ) to do the lookup by name, or some other method. You'd probably want a Dictionary that mapped provider name to the above ConferenceProvider struct.
How would we apply this to something like number identification? At present we look for URLs and keywords then use something likemeeting.conferenceProvider = .attonce we identify the meeting uses AT&T teleconference calls.
â Deco
Mar 6 at 13:40
You would still have that information in the struct I mention above. It would just bemeeting.conferenceProvider.providerName. Or if you wanted it to still be anenumI suppose it could be anenuminstead of aString.
â user1118321
Mar 6 at 17:07
add a comment |Â
up vote
0
down vote
accepted
I think you've used the wrong abstraction here. I think that's the cause of all these switch statements.
Use Objects or structs
One thing I notice is that it seems like a ConferenceProvider should be an object, not an enum. If it were an object you could hold the provider's name, a link to the ConferenceNumberDirectory entry for that provider, the toll key and the toll free key. Then most of your switch statements in the first example go away, and it just becomes extracting the information from the passed-in provider. It could look something like this:
struct ConferenceProvider
let providerName : String
let providerNumbers : [ConferenceNumber]
let tollKey : String
let tollFreeKey : String
init(providerName: String, providerNumbers: [ConferenceNumber], tollKey: String, tollFreeKey: String)
self.providerName = providerName
self.providerNumbers = providerNumbers
self.tollKey = tollKey
self.tollFreeKey = tollFreeKey
You'd then have to change getDirectory(for conferenceProvider: ) to do the lookup by name, or some other method. You'd probably want a Dictionary that mapped provider name to the above ConferenceProvider struct.
How would we apply this to something like number identification? At present we look for URLs and keywords then use something likemeeting.conferenceProvider = .attonce we identify the meeting uses AT&T teleconference calls.
â Deco
Mar 6 at 13:40
You would still have that information in the struct I mention above. It would just bemeeting.conferenceProvider.providerName. Or if you wanted it to still be anenumI suppose it could be anenuminstead of aString.
â user1118321
Mar 6 at 17:07
add a comment |Â
up vote
0
down vote
accepted
up vote
0
down vote
accepted
I think you've used the wrong abstraction here. I think that's the cause of all these switch statements.
Use Objects or structs
One thing I notice is that it seems like a ConferenceProvider should be an object, not an enum. If it were an object you could hold the provider's name, a link to the ConferenceNumberDirectory entry for that provider, the toll key and the toll free key. Then most of your switch statements in the first example go away, and it just becomes extracting the information from the passed-in provider. It could look something like this:
struct ConferenceProvider
let providerName : String
let providerNumbers : [ConferenceNumber]
let tollKey : String
let tollFreeKey : String
init(providerName: String, providerNumbers: [ConferenceNumber], tollKey: String, tollFreeKey: String)
self.providerName = providerName
self.providerNumbers = providerNumbers
self.tollKey = tollKey
self.tollFreeKey = tollFreeKey
You'd then have to change getDirectory(for conferenceProvider: ) to do the lookup by name, or some other method. You'd probably want a Dictionary that mapped provider name to the above ConferenceProvider struct.
I think you've used the wrong abstraction here. I think that's the cause of all these switch statements.
Use Objects or structs
One thing I notice is that it seems like a ConferenceProvider should be an object, not an enum. If it were an object you could hold the provider's name, a link to the ConferenceNumberDirectory entry for that provider, the toll key and the toll free key. Then most of your switch statements in the first example go away, and it just becomes extracting the information from the passed-in provider. It could look something like this:
struct ConferenceProvider
let providerName : String
let providerNumbers : [ConferenceNumber]
let tollKey : String
let tollFreeKey : String
init(providerName: String, providerNumbers: [ConferenceNumber], tollKey: String, tollFreeKey: String)
self.providerName = providerName
self.providerNumbers = providerNumbers
self.tollKey = tollKey
self.tollFreeKey = tollFreeKey
You'd then have to change getDirectory(for conferenceProvider: ) to do the lookup by name, or some other method. You'd probably want a Dictionary that mapped provider name to the above ConferenceProvider struct.
answered Mar 6 at 5:11
user1118321
10.2k11144
10.2k11144
How would we apply this to something like number identification? At present we look for URLs and keywords then use something likemeeting.conferenceProvider = .attonce we identify the meeting uses AT&T teleconference calls.
â Deco
Mar 6 at 13:40
You would still have that information in the struct I mention above. It would just bemeeting.conferenceProvider.providerName. Or if you wanted it to still be anenumI suppose it could be anenuminstead of aString.
â user1118321
Mar 6 at 17:07
add a comment |Â
How would we apply this to something like number identification? At present we look for URLs and keywords then use something likemeeting.conferenceProvider = .attonce we identify the meeting uses AT&T teleconference calls.
â Deco
Mar 6 at 13:40
You would still have that information in the struct I mention above. It would just bemeeting.conferenceProvider.providerName. Or if you wanted it to still be anenumI suppose it could be anenuminstead of aString.
â user1118321
Mar 6 at 17:07
How would we apply this to something like number identification? At present we look for URLs and keywords then use something like
meeting.conferenceProvider = .att once we identify the meeting uses AT&T teleconference calls.â Deco
Mar 6 at 13:40
How would we apply this to something like number identification? At present we look for URLs and keywords then use something like
meeting.conferenceProvider = .att once we identify the meeting uses AT&T teleconference calls.â Deco
Mar 6 at 13:40
You would still have that information in the struct I mention above. It would just be
meeting.conferenceProvider.providerName. Or if you wanted it to still be an enum I suppose it could be an enum instead of a String.â user1118321
Mar 6 at 17:07
You would still have that information in the struct I mention above. It would just be
meeting.conferenceProvider.providerName. Or if you wanted it to still be an enum I suppose it could be an enum instead of a String.â user1118321
Mar 6 at 17:07
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188752%2fclasses-for-representing-teleconferencing-numbers%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
What is the significance of knowing the provider? Why would a user care if AT&T provider the conferencing vs. IBM?
â user1118321
Mar 4 at 21:34
@user1118321 We store phone numbers for these different providers which we will want to put in to the meeting if we detect text or URLs specific to that provider. The user can also store settings for each providers where they can select or put their own number in as well as add participant codes/ host codes for that number. Different providers also use different dial codes.
â Deco
Mar 5 at 14:38
1
let number : String ///The phone numberImagine if you just named the variablelet phoneNumber: String. You wouldn't need a comment. Same withtoll->isTollFree(although that has the inverted meaning)â Alexander
Mar 21 at 18:09