The following code caused the IDE in Xcode to fail, and swiftc throws segmentation fault (11):
func testDeviceWillNotify()
{
let expectation = expectationWithDescription("Will be ready.")
class FooMock: Foo
{
func accessoryDidConnect()
{
expectation.fulfill()
}
}
// ...
}
If I comment out the expectation.fulfill() everything is works correctly. I have also tried expectation! and expectation? but any reference to expectation caused Xcode to crash.
Using Xcode 6.1 (6A1052d) and its extremely frustrating. Does anyone know a way around this bug? Even writing the test another way will have to do.
I don't know how it your code suppose to work because the inner class have to automatically capture variables in the method scope.
This is a workaround
class FooMock: Foo
{
var accessoryDidConnectFunc : (Void -> Void)?
func accessoryDidConnect()
{
accessoryDidConnectFunc ?()
}
}
func testDeviceWillNotify()
{
let expectation = expectationWithDescription("Will be ready.")
let foo = FooMock()
foo.accessoryDidConnectFunc = { expectation.fulfill() }
// ...
}
Related
I'm new in iOS development, so maybe I'm thinking in the wrong way. I coded a view model with a function that calls an API, and everything works fine.
class SearchCityViewModel : ViewModelProtocol {
//OBSERVABLES
var cities = PublishSubject<[City]>()
var networkError = PublishSubject<Void>()
var generalError = PublishSubject<Void>()
init(){
print("Init SearchCityViewModel")
reinit()
}
func reinit(){}
func searchCity(stringToSearch: String){
async {
do {
if stringToSearch.count>=2 {
let cities = try await(api.getCities(cityToSearch: stringToSearch)).payload!
self.cities.onNext(cities)
}
else {
self.cities.onNext([])
}
}
catch {
self.generalError.onNext(Void())
}
}
}
Now I want to handle errors. In the catch block I want to distinguish all the errors I want to handle gracefully, and for the other ones I just want to emit a general error. To do that, firstly I need to know which error is thrown when the situation I want to handle occurs. I usually do this with the debugger. For instance, I disable the internet connection, and i create a breakpoint inside the catch block. The idea is to check which error is thrown when the internet connection is disabled, in order to create a catch block for that kind of error.
Image of the debugger
I'm struggling because with the debugger I only see that is an AFError instance, but it's not telling me nothing more that can help me to catch it.
What is wrong with my workflow? Do I really need to read all the docs every time? For each library I use?
Thank you!
Perhaps you can read the articles and then you will know how to do it better, you can use the framework -oslog instead of using print function.
debugging your logging info
I found the way. What I was missing is casting the error as NSError. In this way, with the debugger is possible to see the domain and the code of the error. In the case of Alamofire, the real error is wrapped, and it's accessible through the underlyingError attribute. Once I had the domain and the code of the error, I wrote the following code:
class SearchCityViewModel : ViewModelProtocol {
//OBSERVABLES
var cities = PublishSubject<[City]>()
var networkError = PublishSubject<Void>()
var generalError = PublishSubject<Void>()
init(){
print("Init SearchCityViewModel")
reinit()
}
func reinit(){}
func searchCity(stringToSearch: String){
async {
do {
if stringToSearch.count>=2 {
let cities = try await(api.getCities(cityToSearch: stringToSearch)).payload!
self.cities.onNext(cities)
}
else {
self.cities.onNext([])
}
}
catch {
if let afError = asAFError, let underlyingError = afError.underlyingError as NSError?, underlyingError.domain == NSURLErrorDomain, underlyingError.code == NSURLErrorNotConnectedToInternet || underlyingError.code == NSURLErrorTimedOut {
self.networkError.onNext(Void())
}
else {
self.generalError.onNext(Void())
}
}
}
}
I am trying to implement a struct with generic type that conforms to Hashable protocol. Can anybody help me understand why am I getting "Segmentation fault: 11" error with the following code.
I would really appreciate any insights regarding this.
struct Pmf<Element: Hashable> {
typealias Distribution = [Element : Float]
fileprivate var normalized = false
fileprivate var distribution:[Element : Float] = [ : ] {
didSet {
self.normalized = false
}
}
}
extension Pmf {
init(values: [Element], withProbs probs: [Float]) {
for pair in zip(values, probs) {
self.distribution[pair.0] = pair.1
}
}
var probDist: Distribution {
mutating get {
if !normalized {
self.normalize()
}
return self.distribution
}
}
subscript(value: Element) -> Float? {
mutating get {
if !normalized {
self.normalize()
}
return self.distribution[value]
}
set(prob) {
self.distribution[value] = prob
}
}
mutating func normalize() {
for (key, val) in self.distribution {
self.distribution[key] = val / Float(self.distribution.count)
}
}
}
var pp = Pmf<String>()
pp["One"] = 4
pp["Two"] = 5
pp["three"] = 5
print(pp)
Seems you need a little trick to define an initializer for a value type in an extension:
Add one line to your init(values:withProbs:) as shown below:
init(values: [Element], withProbs probs: [Float]) {
self.init() //<-
for pair in zip(values, probs) {
self.distribution[pair.0] = pair.1
}
}
Anyway compilers should not crash with SegFault 11. Even if the source code has some fault in it.
You'd better send a Bug Report to Apple, or to swift.org.
I starting writing a bug report for the similar situation (adding method deceleration using a generic with an associated type) and was getting segmentation faults every possible combination I tried.
I started to write a 'Minimum Verifiable Example' in a playground and found I couldn't replicate the fault.
The only difference between app and playground was that app had protocol and method in different source files.
I combined the two source files and no more segmentation fault!!
This took hours of my time to track down, hope it helps someone else.
Update: Submitted a bug for this fault, if you're encountering this too, please add a comment to let the team know you've encountered it: https://bugs.swift.org/browse/SR-3595
I built this project from a meteor app (with meteor build ios...).
I've set it to use the legacy version of Swift (otherwise I get a lot of errors). But when I try to archive it, i get this error in different locations.
func cancel() { // Error: Ambiguous use of 'dispatch_sync(_:block)'
dispatch_sync(queue) {
self._cancel()
}
}
func dispatch_sync(queue: dispatch_queue_t, block: () throws -> ())throws { // 1. Found this candidate
var caughtError: ErrorType?
dispatch_sync(queue) {
do {
try block()
} catch {
caughtError = error
}
}
if let caughtError = caughtError {
throw caughtError
}
}
func cancel() { // 2. Found this candidate
dispatch_sync(queue) {
self._cancel()
}
}
I'm not sure how to solve it, could you help me?
PS: I'm using the latest version of Xcode with MacOS Sierra. And Meteor 1.4.1.2
Rename your function dispach_sync into, for instance, dispatch_sync_mine
How can one write unit tests in Swift that communicate useful information when calling functions that can throw?
What I'd really like to be able to do is something like this:
class TestTestsTests: XCTestCase {
func doFoo() throws -> String {
// A complex operation that might throw in various places
return "foo"
}
func doBar() throws -> String {
// A complex operation that might throw in various places
return "bar"
}
func testExample() throws {
let foo = try doFoo()
let bar = try doBar()
XCTAssertNotEqual(foo, bar)
}
}
Ideally the unit test runner would stop on the line where an unhandled exception occurred, and let the user explore the stack and error message. Unfortunately, adding throws to the test function causes it to be silently skipped over (and there's a UI bug that makes it look as though the test is still being run, and getting the same result as before adding throws).
Of course it is also possible to do this:
func testExample() {
let foo = try! doFoo()
let bar = try! doBar()
XCTAssertNotEqual(foo, bar)
}
But now a failure doesn't really provide the context we need. Add a throw to doFoo, and we get a message like fatal error: 'try!' expression unexpectedly raised an error: TestTestsTests.Error(): file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-700.1.101.15/src/swift/stdlib/public/core/ErrorType.swift, line 50, which only gives us the line number within testExample, and not within doFoo where the error occurred. This also seems to get the debugger 'stuck' (clicking continue just returns us to the same line with the same error message) on that line, regardless of whether breakpoints are enabled, and prevents other tests from running.
So maybe we could try something like this?
func testExample() {
do {
let foo = try doFoo()
let bar = try doBar()
XCTAssertNotEqual(foo, bar)
} catch {
XCTFail("\(error)")
}
}
This runs as expected, however we can't determine which of doFoo or doBar threw the error, and also no line number information. At least we can get the error message and not prevent other tests from running.
I could go on, but the short of it is that I can't find a way to simultaneously not break the unit test running (like with try!), figure out which function threw the error, and get the error information -- Unless I do something ridiculous like:
func testExample() {
var foo: String? = nil
var bar: String? = nil
do {
foo = try doFoo()
} catch {
XCTFail("\(error)")
return
}
do {
bar = try doBar()
} catch {
XCTFail("\(error)")
return
}
if let foo = foo, bar = bar {
XCTAssertNotEqual(foo, bar)
}
}
And I still don't get to find out where in doFoo or doBar the error occurred.
Is this just the sad state of unit testing in Swift, or am I missing something?
This runs as expected, however we can't determine which of doFoo or doBar threw the error, and also no line number information.
Maybe this is just an old problem or I'm not understanding your problem, or maybe you're just kind of making a statement rather than asking a question. But with respect to the quoted statement above, you can add any information you like to the messages in XCTest Assertions.
Swift also provides the following literals:
#file String The name of the file in which it appears.
#line Int The line number on which it appears.
#column Int The column number in which it begins.
#function String The name of the declaration in which it appears.
func testExample() {
var foo: String? = nil
var bar: String? = nil
do {
foo = try doFoo()
} catch {
XCTFail("try doFoo() failed on line: \(#line) in file: \(#file) with error: \(error)")
return
}
do {
bar = try doBar()
} catch {
XCTFail("try doBar() failed on line: \(#line) in file: \(#file) with error: \(error)")
return
}
if let foo = foo, bar = bar {
XCTAssertNotEqual(foo, bar)
}
}
If you really want to go crazy with it you can add error handling to your doBar() method and that error can contain any internal information you'd like.
In fact... by implementing your own errors in your methods you might not even need to separate the methods into two blocks in your tests, just printing the error should be enough. You can put any information you like in the error message.
Anyway, I think this is an outdated issue, you can get all the information you need from the test logs - they list out all the methods that failed and even have little arrows that let you jump right to the test that failed. They then highlight the specific assertion that failed... from there it's quite easy to tell what is happening in most cases. Worst case scenario you have to set a breakpoint or two and run the test again.
You can do your own errors, using Error or LocalizedError protocols
enum Errors: Error, CustomStringConvertible {
case foo_param_is_null
case bar_param_is_null(paramIndex: Int)
var description: String {
switch self {
case .foo_param_is_null:
return "Param is null in foo"
case .bar_param_is_null(let paramIndex):
return "Param at index \(paramIndex) is null in bar"
}
}
}
func foo(_ param: Int) throws {
guard param != 0 else {
throw Errors.foo_param_is_null
}
print("foo = \(param)")
}
func bar(_ params: [Int]) throws {
if let index = params.firstIndex(where: {$0 == 0}) {
throw Errors.bar_param_is_null(paramIndex: index)
}
print("bar = \(params)")
}
do {
try foo(1)
try foo(0)
} catch {
print("\(error)")
}
do {
try bar([1,2,3])
try bar([1,0,3])
} catch {
print("\(error)")
}
Result:
foo = 1
Param is null in foo
bar = [1, 2, 3]
Param at index 1 is null in bar
And if you need even more information, you can use structures to define errors and error domains. Something like :
struct FooBarError: Error, CustomStringConvertible {
var string: String
var context: Any?
static func fooError() {
FooBarError(string: "Foo Error")
}
static func barError(context: BarErrorContext) { FooBarError(string: "Bar Error", context: context)
}
var description: String {
if let cox = context as? BarErrorContext {
return "\(string) - paramIndex: \(ctx.paramIndex) - \(ctx.insidiousReason)"
}
return string
}
}
Note:
As #ibrust proposed, you can pass #function, #line and other special parameters to your errors initialisers to provide this information
do {
try foo()
} catch {
throw(BarFooError.foo(line: #line))
}
You can also propagate the original error
do {
try bar()
} catch {
throw(BarFooError.bar(exception: error))
}
Edited:
Finally , you can also use print(Thread.callStackSymbols) in your error description, but at this point, there is a risk of confusion between debugging and testing. Just a personal thought.
I work with Xcode 7 with swift and I would use the Touch Id. Only I have a error when I use canEvaluatePolicy. I understand my error, I call an argument too. Only if I do not call, it makes me a error because I did not manage my error ...
Here are my error and my code:
PS: sorry for my bad English.
Error : Extra argument 'error' in call
or
Error : Call can throw, but it is not marked with 'try' and the error is not handled
My code :
import Foundation
import UIKit
import LocalAuthentication
class touchid : UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var lblTouchId: UILabel!
override func viewDidLoad() {
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
#IBAction func authenticateWithTouchID(sender: AnyObject) {
let authenticationObject = LAContext()
self.pleaseWait()
if authenticationObject.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics) {
authenticationObject.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Access", reply: {(Bool, authenticationError) in
if authenticationError != nil {
// Authentification annulé ou Touch id non disponible
self.lblTouchId.text = "annulé ou touch id non disponible"
self.clearAllNotice()
self.errorNotice("Erreur !")
}
else {
if Bool == true {
self.lblTouchId.text = "authentification réussi"
self.clearAllNotice()
self.successNotice("Succès !")
}
else {
self.lblTouchId.text = "echec de l'authentification"
self.clearAllNotice()
self.errorNotice("Erreur !")
}
}
}
)
}
}
}
As mentioned in Using Swift with Cocoa and Objective-C, all Objective-C methods that use NSError to return an error object will now throw when called from Swift 2.0, so you need to use:
do {
try method()
} catch let error as NSError {
reportError(error)
}
Removing the reference to NSError in the method() call.
Looking at Apple's documentation, something seems off. The method signature is:
func canEvaluatePolicy(_ policy: LAPolicy, error error: NSErrorPointer) -> Bool
The odd part is that currently, the method doesn't throw anything, so putting it in a do-try block isn't necessary. I don't know if (but my guess is that yes) this framework is still getting tweaked with Swift 2.0, but I thought I remembered it implementing throw at one point in the Xcode/Swift beta iterations. At one point the compiler was acting a little wonky and said that:
1 - the method signature only had 1 parameter, but implements throws (which it doesn't)
2 - But as mentioned above, when you do that, the compiler then gives you different errors.
One thing to point out is that the current method signature, as of this writing, has a second parameter which is an NSErrorPointer, not an NSError? object. Treat it like the current Apple docs suggest, so add something like:
var error: NSErrorPointer?
let canEvaluatePolicty = LAContext().canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: error!)
And your code should compile. It might be a good idea to keep an eye on this framework as more iterations of the beta's come out.
Good Luck!
Although the answer from g_blott does indeed compile, it's not good practice to force unwrap when you're not sure what could happen.
This code also compiles, but doesn't force unwrap anything and handles the existence of an error:
var error: NSError?
let errorPointer: NSErrorPointer = NSErrorPointer(&error)
let canEvaluate = context.canEvaluatePolicy(.deviceOwnerAuthentication, error: errorPointer)
if let error = error {
print("Oh noes, an error! ", error)
} else if canEvaluate {
print("Can evaluate")
} else {
print("Can't evaluate")
}