I am learning Swift. I am designing a class that needs to do parameter validation in it's initializer. How should I handle this if the value passed falls out of range ? I am really finding it difficult to find an appropiate way to design this, considering that:
Swift does not have exceptions, in languages with exceptions and built-in try/catch mechanism, I would have thrown an exception.
Swift does not allow returning nil / null / nothing from the initializer to indicate an error condition, like we can do in Objective-C.
I feel passing an NSErrorPointer to an initializer is cumbersome and places an unneccessary burden on the consumer of the class.
How would you validate a parameter for an initializer in Swift ?
Now with Swift 2.0 you can throw exceptions. For example:
enum Parameter: ErrorType {
case Empty
case Short
}
And then in your functions you can use the super useful guard to check if the received stuff is valid or not and do something like this:
guard parameter.characters.count > 0 else { throw Parameter.Empty }
And then you have to catch those exceptions:
do {
// call your method with try for example something like 'let var = try MyClass("test")'
} catch .Empty {
} catch .Short {
} catch {
print("Something else went wrong!")
}
You can do it using class functions. See below. There are two points to note - the class function has to return Self? not Self, to allow the nil return, and the class must have an #required init().
class Validate {
class func instanceOrNil(valid: Bool) -> Self? {
if valid {
return self()
} else {
return nil
}
}
#required init() {
}
}
let iv = Validate.instanceOrNil(false) // nil
let v = Validate.instanceOrNil(true) // Validate instance
An actual "practical" example might look more like
class NumberLessThanTen {
var mySmallNumber: Int?
class func instanceOrNil(number: Int) -> NumberLessThanTen? {
if number < 10 {
return NumberLessThanTen(number: number)
} else {
return nil
}
}
#required init() {
}
init(number: Int) {
self.mySmallNumber = number
}
}
let iv = NumberLessThanTen.instanceOrNil(17) // nil
let v = NumberLessThanTen.instanceOrNil(5) // valid instance
let n = v!.mySmallNumber // Some 5
One technique: make a Thing.createThing( ... ) class method that wraps the initializer and returns an optional Thing?. Perform the validation inside that method: if the parameters pass validation, call the initializer with them and return the result. If the validation fails, return nil.
Related
I'm using Apollo v0.49.0. It's a library for calling graphQL endpoints, and the way it does this is by generating code before you compile your code.
Before I talk about the generated code, I'd like to talk about what the generated code implements. For this question, it's the GraphQLMutation that's relevant. Here's what it looks like:
public enum GraphQLOperationType {
case query
case mutation
case subscription
}
public protocol GraphQLOperation: AnyObject {
var operationType: GraphQLOperationType { get }
var operationDefinition: String { get }
var operationIdentifier: String? { get }
var operationName: String { get }
var queryDocument: String { get }
var variables: GraphQLMap? { get }
associatedtype Data: GraphQLSelectionSet
}
public extension GraphQLOperation {
var queryDocument: String {
return operationDefinition
}
var operationIdentifier: String? {
return nil
}
var variables: GraphQLMap? {
return nil
}
}
public protocol GraphQLQuery: GraphQLOperation {}
public extension GraphQLQuery {
var operationType: GraphQLOperationType { return .query }
}
public protocol GraphQLMutation: GraphQLOperation {}
public extension GraphQLMutation {
var operationType: GraphQLOperationType { return .mutation }
}
This is 80% of the file; the last 20% is irrelevant IMHO. Note how GraphQLMutation implements GraphQLOperation and the latter has an associatedtype.
The library generates classes based on your graphql server endpoints. Here's what they look like:
public final class ConcreteMutation: GraphQLMutation {
...
public struct Data: GraphQLSelectionSet {
...
}
...
}
As far as I know (I'm new to Swift), I have no control over any of the code I've mentioned so far (other than forking the repo and modifying it). I could change them locally, but they would just be overridden every time they were regenerated.
To use any of these generated classes, I have to pass them into this ApolloClient function (also a library class):
#discardableResult
public func perform<Mutation: GraphQLMutation>(mutation: Mutation,
publishResultToStore: Bool = true,
queue: DispatchQueue = .main,
resultHandler: GraphQLResultHandler<Mutation.Data>? = nil) -> Cancellable {
return self.networkTransport.send(
operation: mutation,
cachePolicy: publishResultToStore ? .default : .fetchIgnoringCacheCompletely,
contextIdentifier: nil,
callbackQueue: queue,
completionHandler: { result in
resultHandler?(result)
}
)
}
I can't figure out how to deal with ConcreteMutation in a generic way. I want to be able to write a factory function like so:
extension SomeEnum {
func getMutation<T: GraphQLMutation>() -> T {
switch self {
case .a:
return ConcreteMutation1(first_name: value) as T
case .b:
return ConcreteMutation2(last_name: value) as T
case .c:
return ConcreteMutation3(bio: value) as T
...
}
}
}
The fact that this func is in an enum is irrelevant to me: that same code could be in a struct/class/whatever. What matters is the function signature. I want a factory method that returns a GraphQLMutation that can be passed into ApolloClient.perform()
Because I can't figure out a way to do either of those things, I end up writing a bunch of functions like this instead:
func useConcreteMutation1(value) -> Void {
let mutation = ConcreteMutation1(first_name: value)
apolloClient.perform(mutation: mutation)
}
func useConcreteMutation2(value) -> Void {
let mutation = ConcreteMutation2(last_name: value)
apolloClient.perform(mutation: mutation)
}
...
That's a lot of duplicated code.
Depending on how I fiddle with my getMutation signature -- e.g., <T: GraphQLMutation>() -> T? etc. -- I can get the func to compile, but I get a different compile error when I try to pass it into ApolloClient.perform(). Something saying "protocol can only be used as a generic constraint because it has Self or associated type requirements."
I've researched this a lot, and my research found this article, but I don't think it's an option if the concrete classes implementing the associated type are final?
It's really difficult to figure out if it's possible to use polymorphism in this situation. I can find plenty of articles of what you can do, but no articles on what you can't do. My question is:
How do I write getMutation so it returns a value that can be passed into ApolloClient.perform()?
The fundamental problem you are running into is that this function signature:
func getMutation<T: GraphQLMutation>() -> T
is ambiguous. The reason it's ambiguous is because GraphQLMutation has an associated type (Data) and that information doesn't appear anywhere in your function declaration.
When you do this:
extension SomeEnum {
func getMutation<T: GraphQLMutation>() -> T {
switch self {
case .a:
return ConcreteMutation1(first_name: value) as T
case .b:
return ConcreteMutation2(last_name: value) as T
case .c:
return ConcreteMutation3(bio: value) as T
...
}
}
}
Each of those branches could have a different type. ConcreteMutation1 could have a Data that is Dormouse while ConcreteMutation3 might have a data value that's an IceCreamTruck. You may be able to tell the compiler to ignore that but then you run into problems later because Dormouse and IceCreamTruck are two structs with VERY different sizes and the compiler might need to use different strategies to pass them as parameters.
Apollo.perform is also a template. The compiler is going to write a different function based on that template for each type of mutation you call it with. In order to do that must know the full type signature of the mutation including what its Data associated type is. Should the responseHandler callback be able to handle something the size of a Dormouse, or does it need to be able to handle something the size of an IceCreamTruck?
If the compiler doesn't know, it can't set up the proper calling sequence for the responseHandler. Bad things would happen if you tried to squeeze something the size of an IceCreamTruck through a callback calling sequence that was designed for a parameter the size of a Dormouse!
If the compiler doesn't know what type of Data the mutation has to offer, it can't write a correct version of perform from the template.
If you've only handed it the result of func getMutation<T: GraphQLMutation>() -> T where you've eliminated evidence of what the Data type is, it doesn't know what version of perform it should write.
You are trying to hide the type of Data, but you also want the compiler to create a perform function where the type of Data is known. You can't do both.
Maybe you need to implement AnyGraphQLMutation type erased over the associatedtype.
There are a bunch of resources online for that matter (type erasure), I've found this one pretty exhaustive.
I hope this helps in someway:
class GraphQLQueryHelper
{
static let shared = GraphQLQueryHelper()
class func performGraphQLQuery<T:GraphQLQuery>(query: T, completion:#escaping(GraphQLSelectionSet) -> ())
{
Network.shared.apollo().fetch(query: query, cachePolicy: .default) { (result) in
switch result
{
case .success(let res):
if let data = res.data
{
completion(data)
}
else if let error = res.errors?.first
{
if let dict = error["extensions"] as? NSDictionary
{
switch dict.value(forKey: "code") as? String ?? "" {
case "invalid-jwt": /*Handle Refresh Token Expired*/
default: /*Handle error*/
break
}
}
else
{
/*Handle error*/
}
}
else
{
/*Handle Network error*/
}
break
case .failure(let error):
/*Handle Network error*/
break
}
}
}
class func peroformGraphQLMutation<T:GraphQLMutation>(mutation: T, completion:#escaping(GraphQLSelectionSet) -> ())
{
Network.shared.apollo().perform(mutation: mutation) { (result) in
switch result
{
case .success(let res):
if let data = res.data
{
completion(data)
}
else if let error = res.errors?.first
{
if let dict = error["extensions"] as? NSDictionary
{
switch dict.value(forKey: "code") as? String ?? "" {
case "invalid-jwt": /*Handle Refresh Token Expired*/
default: /*Handle error*/
break
}
}
else
{
/*Handle error*/
}
}
else
{
/*Handle Network error*/
}
break
case .failure(let error):
/*Handle error*/
break
}
}
}
}
I have a static class like this:
class CDService {
static var initVar:Type?
static var var2:Type2? = {
return initVar?.someProp
}
static func method() {
var2?.doSomething()
}
//....a lot more methods all using var2?
}
Because initVar is optional (require the user to set it before using this service), now var2 has to be optional too.
And then all the methods in this class all of a sudden requires unwrapping. They are use a lot.
Is there a way to refactor this code to just not run if initVar is not yet? I could do a "if let" check in each method but its really tedious. If there is 50 methods?
You can use optional extensions to give default values , I've tried, it's comes really handy when using default datatype optionals.
extension Optional where Wrapped == String { // same goes for other data types
var orEmpty: String {
return self ?? ""
}
var orDash: String {
return self ?? "-"
}
var orZero: String {
return self ?? "0"
}
}
or in your case
extension Optional where Wrapped == Type2 {
var orEmpty: Type2 {
return self ?? Type2()
}
}
I am working on an app and want to get data back from a function. However sometimes data is missing or is different from the kind of that I want to retrieve. I am new to Swift and I can't find a way to write a function that does a little bit of processing and returns this data. When this data is missing, the function should give back a string "Not Found". Like this:
func processData(data:String) {
do {
//processing
var result = processedData
} catch {
var result = "Not Found"
}
return result
}
It would be very nice if somebody could help me.
You should check if the result is nil.
func processData(data: String?) -> String {
guard let result = data else {
return "Not Found"
}
return result
}
The most concise way of doing it would be using the guard-let construct:
func processData(data: String?) -> String {
// Assuming getProcessedData(:) returns your processed data
guard let result = getProcessedData(data) else {
return "Not found"
}
return result
}
Also, your function is missing a return type. You must specify the return type like -> TYPE in all functions that return some value.
Those answer were written till mine are right. There is one way: with handler check get result and use by your point.
enum Errors: Error {
case noData
case unknownError
}
func progress(data: String?, completionHandler: #escaping (_ result: String? , _ error: Error?) -> Void ) {
guard let data = data else {
// Data is missing
throw nil, Errors.noData
}
// Do other things, and throw if necessary
result = data
return result, nil
}
// example of calling this function
process(data: "A data to process"){(result, error) -> Void in
//do any stuff
/*if error == nil {
}*/
}
A good practice in swift would be to use correctly the throws errors
This is an example inspired from yours :
enum Errors: Error {
case noData
case unknownError
}
func progress(data: String?) throws -> String {
guard let data = data else {
// Data is missing
throw Errors.noData
}
// Do other things, and throw if necessary
result = data
return result
}
do {
try process(data: "A data to process")
} catch {
print("An error occurred: \(error)")
}
You can try this code as is in a Swift Playgound
Your function needs to be explicit about returning something with e.g. -> String Also do-catch is for methods that can throw an error. It seems like you need to take a look at how to use optionals. Optionals can have a value or they can have no value.
fun processData(data: String) -> String {
var result: String?
// Do some processing and assign the result to result variable
guard let result = result else { return "Not Found" }
return result
}
I have some generic type class but no instance of object to test. What I would like to do is to alter the behavior of the function according to the runtime type.
class MyGenericUtility<SomeGenericClass> {
func myFunction() {
// so far I have tested "is", "==" and "==="
if SomeGenericClass is SomeRealClass {
println("some special stuff there")
}
println("some generic stuff as the name tells")
}
}
You can compare the class type, using SomeGenericClass.self == SomeRealClass.self as,
class MyGenericUtility<SomeGenericClass> {
func myFunction() {
if SomeGenericClass.self == SomeRealClass.self {
print("SomeRealClass stuffs")
} else if SomeGenericClass.self == String.self {
print("String stuffs")
}
}
}
let someRealUtility = MyGenericUtility<SomeRealClass>()
someRealUtility.myFunction()
let stringUtility = MyGenericUtility<String>()
stringUtility.myFunction()
Rather than testing at runtime, you should generally handle this at compile time with constrained extensions (this assumes Swift 2). Doing it this way avoids any need to do unsafe as! casting when you need to access type-specific parts of the instance.
class MyGenericUtility<SomeGenericClass> {
}
// Special handling for `SomeRealClass`
extension MyGenericUtility where SomeGenericClass: SomeRealClass {
func myFunction() {
print("SomeRealClass stuffs")
}
}
// Default handling for any unspecified class
extension MyGenericUtility {
func myFunction() {
print("Other stuffs")
}
}
let someRealUtility = MyGenericUtility<SomeRealClass>()
someRealUtility.myFunction()
let stringUtility = MyGenericUtility<String>()
stringUtility.myFunction()
Note that this is based on inheritance, not equality, so any subclass of SomeRealClass would get the SomeRealClass behavior.
You can't use the generic type directly, you need to use a property of that type when comparing with "is".
class MyGenericUtility<T> {
var a: T
func myFunction() {
if a is Int {
println("some special stuff there")
}
println("some generic stuff as the name tells")
}
init(value: T) {
a = value
}
}
let test = MyGenericUtility(value: 5)
test.myFunction()
// Output: some special stuff there
// some generic stuff as the name tells
let test2 = MyGenericUtility(value: "foo")
test2.myFunction()
// Output: some generic stuff as the name tells
I have a custom collection that can receive values of any type and converts them to strings. For example:
collection["key"] = 10
let value = collection["key"] // value is a String
Is there a way to do this? I tried implementing two subscript methods but Swift doesn't support write-only subscripts.
subscript(key: String) -> String {
get { ... }
}
// Doesn't compile
subscript(key: String) -> AnyObject {
set { ... }
}
You can use two different subscript implementations and disable the getter for one of them:
subscript(key: String) -> String {
get { return "howdy" } // put real implementation here
}
subscript(key: String) -> AnyObject {
get { fatalError("Oooops") }
set { }
}
However, this still leaves open the question of how to distinguish between these two subscript calls in context. It would be better to give them different signatures through their external parameter names:
subscript(key: String) -> String {
get { return "howdy" } // put real implementation here
}
subscript(# any: String) -> AnyObject {
get { fatalError("Oooops") }
set { }
}
And here's how to use it:
let m = MyClass()
m[any:"thing"] = 1
println(m["thing"]) // "1", presumably
Define subscript to return AnyObject (or Any as needed) and at the point you use the getter cast the result to String. You may already need to deal with subscript returning an optional so the coercion is just all part of extracting your desired value.
if let value = collection["key"] as String { ... }
else {...}
You could also define your own type and make it conform to the IntegerLiteralConvertible and the StringLiteralConvertible protocols.
Technically you could also write an extension for String to make it conform to IntegerLiteralConvertible but that might get confusing, since it will be available in your entire project.
I was facing a similar problem here and I solved it using a generic type for my variable and returning the type I want on its getter. You can try doing something like this:
class StorageClass {
private var _value: String?
public var value: Any? {
set {
if let num = newValue as? Int {
self._value = String(format: "%d",num)
}
}
get {
return self._value
}
}
}
By doing this, it is possible to do something like:
var storage = StorageClass()
storage.value = 10 /* setting value as an Integer */
let aString = storage.value as! String /* receiving a String value back */