Generic Swift struct: Segmentation fault: 11 - ios

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

Related

Swift: how to detect the error type using the debugger?

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())
}
}
}
}

EXC_BAD_ACCESS for arrays in Xcode function

I have this function
func pickAttraction(attractionType: Array<Attraction>) -> Attraction {
let randAttr = attractionType[5]
if favoritesNames.contains(randAttr.attractionName) {
return pickAttraction(attractionType: attractionType)
} else {
return randAttr
}
}
and my program crashes (sometimes) on the line starting with "if favoritesNames". On the last time it crashed, the array favoritesNames had 1 string inside, and randAttr.attractionName had a different string. I expected it to return randAttr, but it crashed instead. Does anyone have any idea why?
I also tried
if favoritesNames.contains(randAttr.attractionName) || favoritesNames[0] == randAttr.attractionName {
and I got the same error
I've also tried
func pickAttraction(from attractions: [Attraction]) -> Attraction? {
attractions.filter { !favoritesNames.contains($0.attractionName) }
.randomElement()
}
instead of the other function and I still get the same error
Thank you
I believe let randAttr = attractionType[5] is accessing an index that doesn't exist. Can you verify that there is available data if you access the array at [5]?

Swift - Ternary conditional operator misunderstanding

I have issues understanding something with ternary conditional operator in Swift 4.1. I hope someone can explain to me :)
I'm using Apollo library.
This library exposes me an object with this field (EDIT) :
public var discount: Swift.Optional<Bool?> {
get {
return graphQLMap["discount"] as! Swift.Optional<Bool?>
}
set {
graphQLMap.updateValue(newValue, forKey: "discount")
}
}
In my class, I'm trying to set this value to true or nil (if value is false, it should be nil to return all results).
Attempt #1 :
func setGoodDeals(_ goodDeals: Bool) {
filters.discount = goodDeals ? goodDeals : nil;
}
This doesn't work ; my app crashes with this error :
Could not cast value of type 'Swift.Optional'
(0x10a9fa298) to 'Swift.Bool' (0x10a9cddf8).
Attempt #2 :
if ( goodDeals ) {
filters.discount = goodDeals;
} else {
filters.discount = nil;
}
This works.
Attempt #3 :
func setGoodDeals(_ goodDeals: Bool) {
filters.discount = goodDeals ? true : nil;
}
This works.
Can anyone explain to me why ?
Thx in advance,
Very simple. It works like this.
Let's say we have to pas the string on the basis of a bool 'isNewUser'.
yourLable.text = isNewUser ? "You can get" : "You get"
if 'isNewUser' is true then it will pass "You can get otherwise it will pass "You get".
I hope it is crystal clear.

Testable Asynchronous Design Pattern in Swift

I'm learning Test Driven Development in Swift. I hit a wall when I realized the delegate pattern I regularly use for asynchronous requests is difficult to test. I've learned that if something's difficult to test, the design pattern behind the implementation could probably be better. This is confusing me because I think the delegate pattern I'm using is common and I'm wondering how others have dealt with this issue.
The pattern:
I wrote a service, which executes an asynchronous request in a static function which takes a delegate instance. The delegate instance conforms to a protocol which requires implementation of a success and failure method. I've contrived an example which hits Google.com. Please ignore the Type safety issues in this example. The actual code I'm running to hit an endpoint and parse JSON is safer. I just wanted to come up with a very small snippet of code to depict the issue that's causing difficulty while testing:
protocol GoogleServiceDelegate {
func gotGoogle(str: String);
func gotError(str: String);
}
struct GoogleService {
static func getGoogle(delegate: GoogleServiceDelegate) {
let url: NSURL! = NSURL(string: "http://google.com")
NSURLSession.sharedSession().dataTaskWithURL(url) { data, response, error in
if let data = data {
let str: NSString! = NSString(data: data, encoding: NSUTF8StringEncoding)
delegate.gotGoogle(str as String)
} else {
delegate.gotError("\(error)")
}
}
}
}
Here's the test which illustrates the problem:
class AsyncTestingTests: XCTestCase {
func testExample() {
let responseExpectation = expectationWithDescription("Got google response!")
struct GoogleDelegate: GoogleServiceDelegate {
func gotGoogle(str: String) {
// expectations about response
responseExpectation.fulfill()
}
func gotError(str: String) {
// expectations about error
responseExpectation.fulfill()
}
}
let myGoogleServiceDelegate = GoogleDelegate()
GoogleService.getGoogle(myGoogleServiceDelegate)
waitForExpectationsWithTimeout(5) { _ in
print("Never got a response from Google :(")
}
}
}
The problem arises at the two .fulfill() lines. I get the following error from Xcode:
Struct declaration cannot close over value 'responseExpectation' defined in outer scope
I understand the error, but am unsure what to adjust... Is there a workaround for this which I can use in the test, or is there a better (easily testable) pattern for asynchronous callbacks than what I am attempting? If you know of a better testable solution, would you mind taking the time to write down an example?
Yes, you can not close over variables defined outside of struct, to workaround, we need to use closures/functions and pass it to the struct. Methods in struct can invoke it when they receive the response.
func testExample() {
let responseExpectation = expectationWithDescription("Got google response!")
//Let a function capture the fulfilling of the expectation
func fullFillExpectation(){
responseExpectation.fullFill()
}
struct GoogleDelegate: GoogleServiceDelegate {
var fullFiller : (()->Void)!
func gotGoogle(str: String) {
// expectations about response via invoke the closure
fullFiller()
}
func gotError(str: String) {
// expectations about error - invoke the closure
fullFiller()
}
}
//Create the delegate with full filler function.
let myGoogleServiceDelegate = GoogleDelegate(fullFiller: fullFillExpectation)
GoogleService.getGoogle(myGoogleServiceDelegate)
waitForExpectationsWithTimeout(5) { _ in
print("Never got a response from Google :(")
}
}
}
PS: I could not test this, please test and let me know.

Swift segmentation fault 11 due to variable scope

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() }
// ...
}

Resources