Swift exc_bad_access when applying a function - ios

A'right guys, I'm stumped.
So I'm working on a functional json implementation along the lines of this article. Things are going fairly well, but I have this one issue that persists in both current and beta versions of Xcode and Swift.
My decode logic takes an argument from the JSON dictionary on the left, and uses a decode function provided on the right, composing them with the 'bind' operator:
return AdUnitDictionary.create <^>
d["adRepeats"] >>> _JSONInt <*>
d["adStartsAfter"] >>> _JSONInt <*>
d["advertisingOn"] >>> _JSONInt <*>
d["numberOfCards"] >>> _JSONInt <*>
d["adUnitIdNonRetina"] >>> _JSONString <*>
d["adUnitIdRetina"] >>> _JSONString
Bind is defined like this:
func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B> {
switch a {
case let .Value(x): return f(x.value)
case let .Error(error): return .Error(error)
}
}
So, originally, this method tries to cast the string and returns a safe, empty string in the event of failure. I thought that I was getting EXC_BAD_ACCESS from my if-let block:
func _JSONString(object: JSON) -> String {
if let object = object as? String { return object } // EXC_BAD_ACCESS
return ""
}
Because that 'if-let' line is where the debugger shows the exception to be thrown. However! Eliminating that block, and using a function that ignores its arguments ENTIRELY, causes the exception to be thrown on the return!!
func _JSONString(object: JSON) -> String {
return "" // EXC_BAD_ACCESS
}
The only sense I can make of this is that the function being applied is nil, since the argument itself is checked to exist in the implementation of bind. This doesn't make sense, however, because the debugger makes it right into my target function before throwing its exception.
Another mystery is why the numeric decodes succeed without any issue, even though they're just carbon-copies of the string decoder with a different type specialization.
Any ideas?

check you pattern!
let object: Int? = nil
if let object = object as? String {
print("a")
} else {
print("nil")
}
// prints nil
or
let object: Int = 1
if let object = object as? String {
print("a")
} else {
print("nil")
}
// prints nil

Related

why does guard break type inference?

I have met a problem like what title has described: the guard statement breaks type inference for some reason. I have created a Playground project to play around.
Here are some boilerplate code for setup:
import Foundation
struct Model: Decodable {
var i: String
}
let jsonString = """
{
"i": "yes"
}
"""
let jsonData = jsonString.data(using: .utf8)
let theModel = try JSONDecoder().decode(Model.self, from: jsonData!)
struct Response<T> {
var decodedData: T?
}
enum Result<Value> {
case success(Value)
case failure
}
struct Client {
static let shared = Client()
private init() {}
func execute<T: Decodable>(completion: (Response<T>) -> ()) {
let decodedData = try! JSONDecoder().decode(T.self, from: jsonData!)
completion(Response(decodedData: decodedData))
}
}
Here's the problem:
struct ServicesA {
func loadSomething(completion: (Result<Model>) -> ()) {
Client.shared.execute { result in // error: generic parameter 'T' could not be inferred
guard let decodedData = result.decodedData else { return }
completion(Result.success(decodedData))
}
}
}
struct ServicesB {
func loadSomething(completion: (Result<Model>) -> ()) {
Client.shared.execute { result in
completion(Result.success(result.decodedData!))
}
}
}
ServicesA breaks whereas ServicesB compiles.
As what you can see, the only difference is guard let decodedData = result.decodedData else { return }. It breaks the type inference so that the Client.shared.execute function complains that the T can't be inferred.
I wonder why would this happen and what's the most appropriate way to deal with this issue.
TLDR; single line closure compilation is different from multi line
Long answer: Let’s forget single line closures for sometime. When we write generic function accepting a generic as argument type and then call this function, compiler needs to know at time of invocation about what’s the type of function needed i.e. the type of its argument. Now consider this argument is a closure. Again compiler needs to know what’s the type of closure (function signature) at time of invocation. This info should be available in the signature of the closure (i.e. argument and return type), compiler doesn’t worry (and rightly so) about the body of the closure. So Service A is behaving perfectly as expected from compiler i.e. the closure signature doesn’t give any clue of its type.
Now comes in single line closure. Swift compiler has a built in type inference optimisation for single line closures only. When you write single line closure, compiler first kicks in its type inference and try to figure out about the closure including its return type etc from its only single line of body . This type inference kicks in for single line closures (with or without the context of generics).
This type inference is the reason that your service B works
So I’ll rephrase the question as “Why does the type inference works for single line closures?” because that’s an extra feature provided by Swift for single line closures only. As soon as you move to multi line closure (its not guard statement specific, same will happen if you put print(“hello world”) as well), this type inference is no more available. Though there may be other type inference checks available for multi line closures.
What you can do is just provide the Type info in closure signature
i.e (result: Response< Model >)
The compiler only infers closure return types when there is a single statement in the closure.
let x = {
return 1
}()
// x == Int(1)
let y = { // error: unable to infer complex closure return type; add explicit type to disambiguate
print("hi")
return 2
}()
https://forums.swift.org/t/problems-with-closure-type-inference/11859/2
You need to type cast it result with Result< Model > so can compiler know about T
struct ServicesA {
func loadSomething(completion:(Result<Model>) -> ()) {
Client.shared.execute { (result:Response<Model>) in
guard let data = result.decodedData else {return}
completion(Result.success(data))
}
}
}
Problem is you are referencing data variable but the compiler doesn't know what type is this (because it is a Generic). Try this:
struct ServicesA {
func loadSomething<T:Model>(completion:(Result<T>) -> ()) {
Client.shared.execute { result:Response<T> in
guard let decodedData = result.decodedData else { return }
completion(Result.success(decodedData))
}
}
}

How to validate values before creating Realm object (in RealmSwift)

My application code gets JSON data from a server, converts it to a Dictionary and then uses that to hydrate and attempt to save a RealmSwift object with a matching schema.
I ran into a crash caused by a Float value coming into a field that was declared as Int in the model. RLMException was thrown.
As suggested in this thread, one doesn't simply try to catch RLMException.
My question is, is that answer correct? And, if so, what is the correct way to prevent a crash when an unexpected value is found? Isn't there some sort of validation mechanism that I can run on all of the values before attempting to set them?
You can use third party frameworks for mapping JSON to Realm objects, like ObjectMapper and use it's failable initializer to validate your JSON.
This failable initializer can be used for JSON validation prior to object serialization. Returning nil within the function will prevent the mapping from occuring. You can inspect the JSON stored within the Map object to do your validation.
You can use this to see if everything is ok with json parameters
static func createFromJSONDictionary(json: JSONDictionary) throws -> MyObject {
guard let
property1 = json["property1"] as? Int,
property2 = json["property1"] as? String else {
// Throw error.... or create with default values
throw NSError(domain: "", code: 0, userInfo: nil)
}
// Everything is fine, create object and return it
let object = MyObject()
object.something = property1
return object
}
I ended up writing an extension to handle this. At the moment I'm only validating numbers and dates, but the switch statement could check every single property type easily.
extension Object {
public convenience init( withDictionary rawData: [String:AnyObject] ) {
var sanitizedData = rawData
let dynamicSelf = self.dynamicType
let schema = dynamicSelf.sharedSchema()
for property in schema.properties {
guard let value = sanitizedData[property.name] else { continue }
var isValid = true
switch property.type {
case .Double:
let val = Double(String(value))
if val == nil || val!.isNaN {
isValid = false
}
case .Float:
let val = Float(String(value))
if val == nil || val!.isNaN {
isValid = false
}
case .Int:
if Int(String(value)) == nil {
isValid = false
}
case .Date:
if Int64(String(value)) == nil {
isValid = false
} else {
sanitizedData[property.name] = NSDate(timeIntervalSince1970: value.doubleValue / 1000)
}
default:
break
}
if !isValid {
log.error( "Found invalid value: \(value) for property \(property.name) of \(dynamicSelf)" )
sanitizedData.removeValueForKey(property.name)
}
}
self.init( value: sanitizedData )
}
}

Check for object type fails with "is not a type" error

I'm trying to check if an object is of a given type and I'm getting an error:
'expectedClass' is not a type
My code below.
func testInputValue(inputValue: AnyObject, isKindOfClass expectedClass: AnyClass) throws {
guard let object = inputValue as? expectedClass else {
// Throw an error
let userInfo = [NSLocalizedDescriptionKey: "Expected an inputValue of type \(expectedClass), but got a \(inputValue.dynamicType)"]
throw NSError(domain: RKValueTransformersErrorDomain, code: Int(RKValueTransformationError.UntransformableInputValue.rawValue), userInfo: userInfo)
}
}
I'm trying to figure out what can be wrong here.
You should be able to do this with generics:
func testInputValue<T>(inputValue: AnyObject, isKindOfClass expectedClass: T.Type) throws {
guard let object = inputValue as? T else {
...
}
}
You should not do class comparisons with == as suggested in one of the other answers, unless you specifically want to test if the type of the object tested should exactly match the expected class and it is not allowed to be a subclass of the tested class.
You can use the instance method isKindOfClass to accomplish this, taking subclassing into account. See below for a code example.
NOTE: You may be surprised that this works on a pure Swift class type, given an instance method with the same name exists in NSObject / NSObjectProtocol. It does indeed work in pure Swift (as shown with the example code below – tested with Xcode 7.3, Swift 2.2.1), with no #objc types involved, as long as you import Foundation. I am presuming based on this that this instance method is added as an extension method in Foundation to all class types.
import Foundation
class A { }
class B { }
class C: B { }
enum ValueTestError: ErrorType {
case UnexpectedClass(AnyClass)
}
func testInputValue(inputObj:AnyObject, isKindOfClass expectedClass:AnyClass) throws {
guard inputObj.isKindOfClass(expectedClass) else {
throw ValueTestError.UnexpectedClass(inputObj.dynamicType)
}
}
let a = A()
let b = B()
let c = C()
do {
try testInputValue(c, isKindOfClass: B.self)
} catch {
print("This does not get printed as c is of type B (C is subclass of B).")
}
do {
try testInputValue(a, isKindOfClass: B.self)
} catch {
print("This gets printed as a is not of type B.")
}
Also, importantly although isKindOfClass is available as an instance method on AnyObject, trying to call it on an arbitrary Swift class typed object will only work if you first cast that object to AnyObject (which will always of course succeed). Example code illustrating this point is presented below, and there's more on this question over here.
import Foundation
class A {}
let a = A()
// the following compiles and returns 'true'
(a as AnyObject).isKindOfClass(A.self)
// the following fails to compile with "Value of type 'A' has no member 'isKindOfClass'"
a.isKindOfClass(A.self)
Not the greatest answer ever, but comparing with inputValue.dynamicType works:
if inputValue.dynamicType == expectedClass {
print("inputValue.dynamicType \(inputValue.dynamicType) equals expectedClass \(expectedClass)")
// ...
}

Calling async function in lazy var property

Is there a way to call an async function from a lazy or computed property?
struct Item {
lazy var name: String = {
API.requestThing({ (string: String) in // Xcode didn't like this
return string // this would not work here
})
}()
}
class API {
class func requestThing(completion: String -> Void) {
completion("string")
}
}
Your completion handler in API.requestThing returns a String, yet it is supposed to have no return value:
(completion: String -> Void)
I got this to work:
struct Item {
lazy var name: String = {
API.requestThing({ (string: String) in
return string
})
}()
}
class API {
class func requestThing(completion: String -> String) -> String {
return completion("string")
}
}
There is no good reason to use "lazy" in this case. lazy is for initialization. Just create a normal func and pass a completion handler.
First, requestThing returns () (ie void) and not String. So the type of the following expression is also () and not String:
API.requestThing { string in
return string
}
Second, the call to requestThing is asynchronous, so even if you defined name as a lazy var, the call to the var body function is still synchronousand will return immediately.
So if you can transform name into a function like this:
func name(completion: String -> ()) {
API.requestThing { string in
completion(string)
}
}
// Later you call it in this way
myItem.name { name in
// use the value of name
}
If in addition you want to cache the retrieved value you can modify Item to a class and use the following code
class Item {
private var nameValue: String?
func name(completion: String -> ()) {
if let value = nameValue {
// return cached value
return completion(value)
} else {
// request value
API.requestThing { string in
// cache retrieved value
self.nameValue = string
// return retrieved value
completion(string)
}
}
}
}
There's probably no compelling reason to do this, but the following approach seems to be reasonable:
Instead having a variable of type String - we sometimes require a "Future" of that thing, e.g. Future<String>. A future represents the eventual result of an asynchronous operation - that is exactly what's given in your question.
The future itself is a "normal" variable and can be lazy evaluated, too. It just doesn't yet have its eventual value. That means, the underlying task will only be started when explicitly requested (e.g. lazily). From a design or architectural point of view, this may make sense.
func fetchString() -> Future<String> { ... }
lazy var name: Future<String> = fetchString()
Later in your code, you obtain the variable as follows:
item.name.map { string in
print(string)
}
If this is the first access to the lazy property, it will start the underlying asynchronous operation which calculates the string. Then, when the variable is available, the mapping function as provided in the map function will be called with the variable as an argument - possibly some time later, too.
Otherwise (if this is not the first access), it will just provide the string in the parameter when it is available, possibly immediately.
Since operations may fail, a "Future" also provides means to handle this:
item.name.map { string in
print(string)
}.onFailure { error in
print("Error: \(error)")
}
See also: https://en.wikipedia.org/wiki/Futures_and_promises
There are implementations for Futures in Swift and Objective-C, also often called "Promise".

Swift conversion issue

Converting some of my code from Objective-C to Swift. Got stuck in a combination of typecasting statement:
if (![[array objectAtIndex:0] isKindOfClass:[BaseView class]]) {
//Throw an exception
}
Since the branching should throw an exception, I am using guard statement instead of if-else. So far I have done the following:
guard NSArray(array: array).objectAtIndex(0) else {
//throw SomeException
}
Please guide the remaining part, how to use the isKindOfClass, also I doubt the correctness of NSArray typecasting
The more correct method is to use is, as its meant to replace isKindOfClass.
guard array.first is BaseView else {
// Throw exception if its not a BaseView subclass
}
The following works in your case:
guard let arr0 = array.first as? BaseView else {
return // or throw exception
}
You try to cast the value in array.first to BaseView and if that conversion fails you will enter the else block and can throw an exception if you wish. Additionally (thanks to #Adam) that will return/throw if the array is empty. If you have to check for the 3rd element to be of a certain type, you should check that the array actually contains at least 3 values.
Consider the following example:
func t(arr : [AnyObject]) {
guard let arr0 = arr.first as? String else {
return
}
print(arr0)
}
t(["asd", 123]) // prints something
t([123, "asd"]) // returns without printing anything
t([]) // returns without printing anything

Resources