Have a variable with multiple types in Swift
Here is how you can achieve it. Works exactly how you'd expect.
protocol StringOrInt { }
extension Int: StringOrInt { }
extension String: StringOrInt { }
var a: StringOrInt = "10"
a = 10 //> 10
a = "q" //> "q"
a = 0.8 //> Error
NB! I would not suggest you to use it in production code. It might be confusing for your teammates.
UPD: as @Martin R mentioned: Note that this restricts the possible types only “by convention.” Any module (or source file) can add a extension MyType: StringOrInt { }
conformance.
How to define a variable with multiple specific custom types ? (in Swift)
Seems like you need to use protocols
.
Something like:
protocol CustomType {
// your definitions ...
}
extension String: CustomType {}
extension Int: CustomType {}
let customType1: CustomType = "string"
print(customType1)
let customType2: CustomType = 0
print(customType2)
// Error: Value of type 'Double' does not conform to specified type 'CustomType'
// let customType3: CustomType = 0.0
In this case, values of CustomType
type will only accept String
and Int
types (because of the protocol conformance).
Swift: Modeling a variable with multiple types
Since you want to use Swift I'd suggest using protocols. That would give what you need. Simple example:
protocol Sound {
let title: String { get }
let length: TimeInterval { get }
}
The protocol would define the interface. Then you can just create various classes which would conform to the protocol - the underlaying implementation can be completely different:
class Song: Sound {
var title: String
var length: TimeInterval
init(title: String, length: TimeInterval) {
self.title = title
self.length = length
}
}
class Artist: Sound {
var title: String {
return "Artist"
}
var length: TimeInterval {
return 11.1
}
}
Then you can simply access title
on any object conforming to the Sound
protocol:
let sound1: Sound = Song(title: "Song", length: 1)
let sound2: Sound = Artist()
print("\(sound1.title)") // prints: Song
print("\(sound2.title)") // prints: Artist
Allow Swift function parameter to be of multiple types
You mentioned enums, which sound like an excellent fit for this use case.
You can explicitly only require the types you expect, and nothing else.
By adding a property to the enum you can then expose a UIControl
property to interact as needed, without the need for down-casting (which is generally considered to be an anti-pattern).
enum Component {
case `switch`(UISwitch)
case stepper(UIStepper)
var control: UIControl {
switch self {
case .switch(let comp):
return comp
case .stepper(let comp):
return comp
}
}
}
Then ask for a Component
as a parameter to the function.
func controlValueChanged(_ myComponent: Component) {
// Now you can use them as a generic UIControl
let control = myComponent.control
// ...or different behaviours for each element
switch myComponent {
case .switch(let swit):
// use the `swit`
case .stepper(let step):
// use the `step`
}
}
Having said that, if the implementations for these types are totally different anyway, it may be more clear to define two separate functions.
Multiple types in function
A possible solution is to add a protocol
protocol Reusable {
var delegate : ReusableDelegate { get set } // change the type to the real delegate type
}
and constrain the generic type to the protocol. You should constrain the generic type to UITableViewCell
anyway
func configureQuestionCell<T>(cellType: T) where T : UITableViewCell & Reusable {
let cell = self.blockContent.dequeueReusableCell(withIdentifier: ReusableCellID.ratingCell.rawValue) as! T
cell.delegate = self
}
For multiple different delegate types use an associated type
protocol Reusable {
associatedtype DelegateType
var delegate : DelegateType { get set }
}
And in the cell adopt the protocol and add
typealias DelegateType = < The actual delegate type of the cell >
multiple types in Codable
I definitely agree with @vadian. What you have is an optional rating. IMO this is a perfect scenario for using a propertyWrapper. This would allow you to use this Rated type with any model without having to manually implement a custom encoder/decoder to each model:
@propertyWrapper
struct RatedDouble: Codable {
var wrappedValue: Double?
init(wrappedValue: Double?) {
self.wrappedValue = wrappedValue
}
private struct Rated: Decodable {
let value: Double
}
public init(from decoder: Decoder) throws {
do {
wrappedValue = try decoder.singleValueContainer().decode(Rated.self).value
} catch DecodingError.typeMismatch {
let bool = try decoder.singleValueContainer().decode(Bool.self)
guard !bool else {
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Corrupted data"))
}
wrappedValue = nil
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
guard let double = wrappedValue else {
try container.encode(false)
return
}
try container.encode(["value": double])
}
}
Usage:
struct AccountState: Codable {
let id: Int?
let favorite: Bool?
let watchlist: Bool?
@RatedDouble var rated: Double?
}
let json1 = #"{"id":550,"favorite":false,"rated":{"value":9.0},"watchlist":false}"#
let json2 = #"{"id":550,"favorite":false,"rated":false,"watchlist":false}"#
do {
let accountState1 = try JSONDecoder().decode(AccountState.self, from: Data(json1.utf8))
print(accountState1.rated ?? "nil") // "9.0\n"
let accountState2 = try JSONDecoder().decode(AccountState.self, from: Data(json2.utf8))
print(accountState2.rated ?? "nil") // "nil\n"
let encoded1 = try JSONEncoder().encode(accountState1)
print(String(data: encoded1, encoding: .utf8) ?? "nil")
let encoded2 = try JSONEncoder().encode(accountState2)
print(String(data: encoded2, encoding: .utf8) ?? "nil")
} catch {
print(error)
}
This would print:
9.0
nil
{"watchlist":false,"id":550,"favorite":false,"rated":{"value":9}}
{"watchlist":false,"id":550,"favorite":false,"rated":false}
Swift - check if instance is one of multiple types
You can use type(of:)
and .contains
:
let types = [A.self, C.self]
let test = A()
if types.contains(where: { $0 == type(of:test) }) {
print("Here")
}
Related Topics
Uitextfield -Webview No Longer Supported
How Come I Can Cast to Nsmanagedobject But Not to My Entity's Type
How to Tap on a Specific Point Using Xcode Uitests
Fbsdkloginmanager Loginwithpublishpermissions Always Returns Iscancelled=Yes
Wkwebview Function for Detecting If the Url Has Changed
Skspritenode - Create a Round Corner Node
iOS 14 How to Trigger Local Network Dialog and Check User Answer
Destinationviewcontroller Segue and Uinavigationcontroller Swift
Found an Unexpected MACh-O Header Code: 1918975009 in Xcode 6
How to Get Directions in Mkmapview Using a Built in Apple API
Using Mdm to Configure an Enterprise App via Nsuserdefaults
How to Calculate the Uilabel Height Dynamically
Capture Uiview and Save as Image