Swift 2.2: Segmentation fault: 11 - ios

I am getting a segfault: 11 after updating to the latest version of Xcode (7.3). The code that is triggering this is:
private func makeScreenshots(points points_I: [[CGPoint]], frames frames_I: [[CGRect]], scale:CGFloat, completion: (screenshots: [[UIImage]]) -> Void) {
var counter: Int = 0
// use didSet as a responder to the completion handler,instead of a loop, ensuring nice sequential execution
var images: [[UIImage]] = [] {
didSet {
if counter < points_I.count {
internalScreenshotRow()
} else {
completion(screenshots: images)
}
}
}
// same code is used twice -> nested function
func internalScreenshotRow() {
makeScreenshotRow(points: points_I[counter], frames: frames_I[counter], scale: scale) { (screenshot) -> Void in
counter += 1
images.append(screenshot)
}
}
internalScreenshotRow() // start first run
}
private func makeScreenshotRow(points points_I: [CGPoint], frames frames_I: [CGRect], scale:CGFloat, completion: (screenshots: [UIImage]) -> Void) {
var counter: Int = 0
// use didSet as a responder to the completion handler,instead of a loop, ensuring nice sequential execution
var images: [UIImage] = [] {
didSet {
if counter < points_I.count {
internalTakeScreenshotAtPoint()
} else {
completion(screenshots: images)
}
}
}
// same code is used twice -> nested function
func internalTakeScreenshotAtPoint() {
takeScreenshotAtPoint(point: points_I[counter], scale: scale) { (screenshot) -> Void in
counter += 1
images.append(screenshot)
}
}
internalTakeScreenshotAtPoint() // start first run
}
The error being thrown by compiler is:
1. While emitting SIL for 'makeScreenshots' at /ScrollViewImager.swift:115:13
2. While emitting SIL for 'internalScreenshotRow' at /ScrollViewImager.swift:131:9
3. While silgen closureexpr SIL function #_TFFFE8BeamItUpPS_16ScrollViewImagerP33_22F49B169CD6FD663C230349D2C79AE615makeScreenshotsFT6pointsGSaGSaVSC7CGPoint__6framesGSaGSaVSC6CGRect__5scaleV12CoreGraphics7CGFloat10completionFT11screenshotsGSaGSaCSo7UIImage___T__T_L_21internalScreenshotRowFT_T_U_FGSaS5__T_ for expression at [/ScrollViewImager.swift:132:99 - line:135:13] RangeText="{ (screenshot) -> Void in
counter += 1
images.append(screenshot)
}"
The ScrollViewImager is an open source library for taking screenshots of scrollview Reference

Related

Screen freezing for large task execution

I am trying to use completion block but still screen is freezing may I know what is wrong here? Or how can I improve?
func generateRandom(text: String, frame: CGRect,
stackFont: [StackTextFont], completion: #escaping (StackableTextStyle) -> Void) {
var style = generateStyle(text: text, frame: frame, stackFont: stackFont)
var maxCounter = 0
while style == nil || !isValidStyleForFrameSize(style!.0, frame: frame, stackFonts: style!.1.fonts) {
style = generateStyle(text: text, frame: frame, stackFont: stackFont)
maxCounter = maxCounter + 1
if maxCounter > loopBreakerAt {
break
}
print(maxCounter)
}
completion(style ?? (text, StackTextGroup(fonts: stackFont)))
}
Note: Assume that loop might execute more than 100000 time to get the validate style
Calling the function
var i = 10
var counter = 1
let group = DispatchGroup()
while i > 0 {
group.enter()
QuoteNeuralParser.shared.generateRandom(text: text, frame: frame, stackFont: stackFont) { (style) in
/// Avoid duplicate styles
if !self.data.contains(where: {$0.1.1.fonts == style.1.fonts}) {
if let img = self.getIMStackLayer(frame: frame, style: style).toUIImage() {
self.data.append((img, style))
i = i - 1
}
}
/// Loop breaker for infinite attempt
counter += 1
if counter > 30 { i = -1 }
group.leave()
}
}
group.notify(queue: .main) { [weak self] in
guard let self = self else {
return
}
}

How to create a closure inside a closure? [duplicate]

This question already has answers here:
Calling Swift Closure Inside Closure
(4 answers)
Closed 4 years ago.
I am trying to create a function in Swift so I can make a repeating animation (I know you can use .repeat, but I do not want to use that). In my completion closure, I am getting an error. Here is my code so far:
import UIKit
var withDurationVar:TimeInterval = 0
var optionsVar:UIViewAnimationOptions?
var iterateVar = 0
var animationsVar:(() -> ()?)?
var completionVar:(() -> ()?)?
var numberOfIterations = 0
func repeatingAnimation(withDuration:TimeInterval, options:UIViewAnimationOptions, iterate:Int, animations:#escaping () -> (), completion:#escaping () -> ()) {
withDurationVar = withDuration
optionsVar = options
iterateVar = iterate
animationsVar = animations
completionVar = completion
}
func animationRepeat() {
UIView.animate(withDuration: withDurationVar, delay: 0, options: optionsVar!, animations: animationsVar as! () -> Void, completion: { (Finished) in
// Increase number of iterations
numberOfIterations += 1
// If it has not yet done every iteration needed
if numberOfIterations != iterateVar {
// Repeat animation
animationRepeat()
}
else {
completionVar // Where I get an error. 'Expression resolves to an unused I-value'
}
})
}
I can do this however:
func animationRepeat() {
UIView.animate(withDuration: withDurationVar, delay: 0, options: optionsVar!, animations: animationsVar as! () -> Void, completion: completionVar)
}
So how can I have the completion from my repeatingAnimation function into the completion of animationRepeat with the rest of the code as well? Thanks!
I have updated my code if anyone want to use it as a repeating animation function :)
import UIKit
// Make some variables to be accessed across the file
var withDurationVar:TimeInterval = 0
var optionsVar:UIViewAnimationOptions?
var iterateVar = 0
var animationsVar:(() -> ()?)?
var completionVar:(() -> ()?)?
var numberOfIterations = 0
// The function to call
func repeatingAnimation(withDuration:TimeInterval, options:UIViewAnimationOptions, iterate:Int, animations:#escaping () -> (), completion:#escaping () -> ()) {
// Set the global variables from the parameters
withDurationVar = withDuration
optionsVar = options
iterateVar = iterate
animationsVar = animations
completionVar = completion
// Has not started repeating yet
numberOfIterations = 0
// Start repeat
animationRepeatForFunction()
}
// The function which is ONLY called by the repeatingAnimation or itself, not the user
func animationRepeatForFunction() {
UIView.animate(withDuration: withDurationVar, delay: 0, options: optionsVar!, animations: {animationsVar?()}, completion: { (Finished) in
// Increase number of iterations
numberOfIterations += 1
// If it has not yet done every iteration needed
if numberOfIterations < iterateVar {
// Repeat animation
animationRepeatForFunction()
}
else {
// Perform what the user wanted to do after the repeating animation
completionVar?()
}
})
}
Call the function using repeatingAnimation(...)
The .repeat function can only really be used for infinite loops, which do not need to be stopped. In my case, I wanted to repeat a finite amount of times (terminates), so I made this custom function which can have its own .swift file.

Delay for Retry - RxSwift

Is there elegant solution for creating delay for retry? When error occurs I want to wait for 5 seconds and restart Observable (retry)
Just create a PrimitiveSequence extension that wraps around retry().
(Swift5.1 RxSwift 4.3.1)
extension PrimitiveSequence{
func retry(maxAttempts: Int, delay: TimeInterval) -> PrimitiveSequence<Trait, Element> {
return self.retryWhen { errors in
return errors.enumerated().flatMap{ (index, error) -> Observable<Int64> in
if index < maxAttempts {
return Observable<Int64>.timer(RxTimeInterval(delay), scheduler: MainScheduler.instance)
} else {
return Observable.error(error)
}
}
}
}
}
Usage example: (retry 3 times, with 2 sec delay each)
yourRxStream.retry(maxAttempts: 3, delay: 2)
Here is the code for swift 4.0+
// sample retry function with delay
private func sampleRetryWithDelay(){
let maxRetry = 3
let retryDelay = 1.0 // seconds
let _ = sampleStreamWithErrors() // sample observable stream, replace with the required observable
.retryWhen { errors in
return errors.enumerated().flatMap{ (index, error) -> Observable<Int64> in
return index < maxRetry ? Observable<Int64>.timer(RxTimeInterval(retryDelay), scheduler: MainScheduler.instance) : Observable.error(error)
}
}.subscribe(onNext:{ value in
print("Result:\(value)")
})
}
// Sample stream with errors, helper function only - generating errors 70% of the time
private func sampleStreamWithErrors() -> Observable<Int>{
return Observable.create { observer in
let disposable = Disposables.create() {} // nothing to cancel, we let it complete
let randomInt = Int(arc4random_uniform(100) + 1)
if randomInt > 70 {
observer.on(.next(randomInt))
observer.on(.completed)
} else {
let sampleError = NSError(domain: "SampleDomain", code: randomInt, userInfo: nil)
print("Result:Error:\(randomInt)")
observer.on(.error(sampleError))
}
return disposable
}
}

iOS - Type 'DispatchQueue' has no member 'GlobalAttributes'

I have the following error:
Type 'DispatchQueue' has no member 'GlobalAttributes'
In my code. Do you know why?
public typealias Classification = (Label: DigitLabel, Confidence: CGFloat, BestPrototypeIndex: Int)
public func classifyDigit(digit: DigitStrokes, votesCounted: Int = 5, scoreCutoff: CGFloat = 0.8) -> Classification? {
if let normalizedDigit = normalizeDigit(inputDigit: digit) {
let serviceGroup = DispatchGroup()
let queue = ***DispatchQueue.global(attributes: DispatchQueue.GlobalAttributes.qosUserInitiated)***
let serialResultsQueue = DispatchQueue(label: "collect_results")
var bestMatches = SortedMinArray<CGFloat, (DigitLabel, Int)>(capacity: votesCounted)
for (label, prototypes) in self.normalizedPrototypeLibrary {
queue.async(group: serviceGroup) {
var localBestMatches = SortedMinArray<CGFloat, (DigitLabel, Int)>(capacity: votesCounted)
var index = 0
for prototype in prototypes {
if prototype.count == digit.count {
let score = self.classificationScore(sample: normalizedDigit, prototype: prototype)
//if score < scoreCutoff {
localBestMatches.add(value: score, element: (label, index))
//}
}
index += 1
}
serialResultsQueue.async(group: serviceGroup) {
for (score, bestMatch) in localBestMatches {
bestMatches.add(value: score, element: bestMatch)
}
}
}
}
I also attached the file, just in case.
According to Apple's documentation, the message is correct.
Maybe you want to use DispatchQueue.Attributes?
EDIT:
I just had a closer look at the documentation:
DispatchQueue.global() seems to be changed. The documentation shows this declaration:
class func global(qos: DispatchQoS.QoSClass = default) -> DispatchQueue
I tested some variations, Xcode proposed and found this line:
let queue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated)
I did not test, if this works 100% with your example, but Xcode will compile it

How to make a "for" loop on the condition of a number interval Xcode Swift2

Hey I'm trying to figure out how to tally up soccer goals on the condition that the goal was scored in under 45 minutes, but the func has some slight errors with swift 2. Any help? Thanks!
Code:
var barcelonavsRealMadrid1goals : [String : Int] = ["barcelonaGoal1":21,"RealMadridGoal2":23,"barcelonaGoal3":24,"RealMadridGoal4":27]
func Run() {
var goalCount=0
for (goal,numbers) in barcelonavsRealMadrid1goals{
for(var number in numbers) {
if(number < 45)
goalCount++
}
}
You have an extra for..in loop in there that's not needed:
for(var number in numbers) {
It also has an extraneous ( and ) around it
for var number in numbers {
Here is a working version of your code:
var barcelonavsRealMadrid1goals = ["barcelonaGoal1":21,"RealMadridGoal2":23,"barcelonaGoal3":24,"RealMadridGoal4":27]
func run() -> Int { // functions should start with lower case
var goalCount=0
for (_,numbers) in barcelonavsRealMadrid1goals where numbers < 45 {
goalCount++
}
return goalCount
}
let goalCount = run()
And the functional way would be something like:
let goalCount = goals.reduce(0) {
if $0.1.1 < 45 {
return $0.0 + 1
}
return $0.0
}
With explanation:
var goals = [
"barcelonaGoal1" :21,
"RealMadridGoal2":23,
"barcelonaGoal3" :24,
"RealMadridGoal4":27,
"RealMadridGoal5":45]
// For our use reduce takes an initial value of Int
// and a combine function of type
// (Int, (String, Int)) -> Int
//
// Reduce will call the closure once with
// each value in the map and the previous return value
let goalCount = goals.reduce(0, combine: {
(initial:Int, current:(key:String, value:Int)) -> Int in
var currentCount = initial
// print to show input and output of closure
print( "parameters:(\(initial), (\"\(current.key)\", \(current.value)))", terminator:", ")
defer {
print("return:\(currentCount)")
}
// end printing
if current.value < 45 {
++currentCount // add 1 to the running total
return currentCount
}
return currentCount
})
// console output:
// parameters:(0, ("barcelonaGoal1", 21)), return:1
// parameters:(1, ("RealMadridGoal4", 27)), return:2
// parameters:(2, ("RealMadridGoal5", 45)), return:2
// parameters:(2, ("RealMadridGoal2", 23)), return:3
// parameters:(3, ("barcelonaGoal3", 24)), return:4
For solving of you're problem try to use functional programing that is introduced in swift :
var barcelonavsRealMadrid1goals : [String : Int] = ["barcelonaGoal1":95,"RealMadridGoal2":23,"barcelonaGoal3":24,"RealMadridGoal4":27]
var filtered = barcelonavsRealMadrid1goals.filter { (team:String, minute:Int) -> Bool in
var state = false
if (minute > 45)
{
return true
}
return state
}
let totalCount = filtered.count
Try this method.
func Run() {
var goalCount=0
for (_, score) in barcelonavsRealMadrid1goals {
if(score < 45) {
goalCount++
}
}
print(goalCount)
}

Resources