iOS UI freezes up on heavy "String to Binary" conversions

My app is in its final stage and I am doing some "last minute" testing. Everything else works like it's supposed to but one problem I noticed was when I attempt to convert a string of 660 characters to binary the UI completely freezes up until the entire conversion is complete, due to the heavy encoding activity.

I tried to implement Dispatch
Code Block
Dispatch.main.async { /* Code */ }
in my main encoding function meanwhile implementing
Code Block
Dispatch.gloabl(qos: .default).async { /* Main encoding sequence code */ }
(where "main encoding sequence code" is the encoding algorithm) but I am still getting the freezes. Then I tried to do THAT but instead of encoding the whole string, I split the string up. Basically, when the encoding algorithm is called, the string will be encoded every 50 characters.

One other thing is, it's only doing that for Binary Encoding. Every other encoding method handles 660 characters just fine.

I just want to know how I can eliminate the freezing UI (until the operation is complete) more efficiently. I have posted the full operation below (I also implemented a function for when the string is over 100 characters):
Code Block
import UIKit
import Foundation
class ViewController: UIViewController {
    // MARK:- Outlet init
    @IBOutlet weak var sourceString: UITextField!
    @IBOutlet weak var resultOutput: UITextView!
@IBOutlet weak var encode: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()
    }
// MARK:- The main encoding function
@IBAction func btnEncode(_ sender: Any) {
if sourceString.text!.count > 100 {
                displayErrorMessage(title: "Long String Alert", message: "This is a pretty long string, this may take a bit to convert to binary, please hold...(String length = " + String(source.count), buttonTitles: "Okay");
                encodeBinaryWhenCharOverlimit(input: source)
            }
            DispatchQueue.main.async {
                // Run UI Updates
                self.encodeStringBinary(string: source); return
            }
}
    
    // MARK:- Add-In functions and methods
    private func toBinaryStringArray(array:[UInt8]) -> [String] {
        DispatchQueue.global(qos: .default).sync {
            var result:[String] = []
            for e in array {
                let bin = byteToBinaryString(byte: e)
                result.append(bin)
            }
            return result;
        }
    }
    private func byteToBinaryString(byte:UInt8) -> String {
        DispatchQueue.global(qos: .default).sync {
            var result = String(byte, radix: 2)
            while result.count < 8 {
                result = "0" + result
            }
return result;
        }
    }
    // MARK:- Extensible extra functions and methods
    // This function is called when the input string is over 100 characters
    private func encodeBinaryWhenCharOverlimit(input: String) -> Void {
        DispatchQueue.main.async {
            var bytes:[UInt8] = []
            for char in input.utf8 {
                bytes += [char]
            }
 
            // Output the result
            for n in self.toBinaryStringArray(array: bytes) {
                self.resultOutput.text.append(n.inserting(separator: " ", every: 50))
            }; sleep(1)
        }
    }
    // MARK:- Binary Encoding algorithm
    private func encodeStringBinary(string: String) -> Void {
        // var byte = string.utf8.count
        var bytes:[UInt8] = []
      
        for char in string.utf8 {
            bytes += [char]
        }
        // Output the result
        for x in self.toBinaryStringArray(array: bytes) {
            self.resultOutput.text.append(x)
        }
    }
}
// MARK:- Extensions
extension Collection {
    func distance(to index: Index) -> Int { distance(from: startIndex, to: index) }
    func subSequences(limitedTo maxLength: Int) -> [SubSequence] {
            precondition(maxLength > 0, "groups must be greater than zero")
            return .init(sequence(state: startIndex) { start in
                guard start < self.endIndex else { return nil }
                let end = self.index(start, offsetBy: maxLength, limitedBy: self.endIndex) ?? self.endIndex
                defer { start = end }
                return self[start..<end]
            })
        }
        var pairs: [SubSequence] { subSequences(limitedTo: 2) }
}
extension StringProtocol where Self: RangeReplaceableCollection {
    mutating func insert<S: StringProtocol>(separator: S, every n: Int) {
        for index in indices.dropFirst().reversed()
            where distance(to: index).isMultiple(of: n) {
            insert(contentsOf: separator, at: index)
        }
    }
    func inserting<S: StringProtocol>(separator: S, every n: Int) -> Self {
        var string = self
        string.insert(separator: separator, every: n)
        return string
    }
}

Answered by OOPer in 640597022
Simply and frankly speaking, your code is full of inefficient operations and mis-usages of DispatchQueue.

On my machine, a little bit more efficient code takes 7 msec to convert 660 ASCII characters.
You may not want to use DispatchQueue for this short period of freezing.
Code Block
@IBAction func btnEncode(_ sender: Any) {
let source = sourceString.text ?? ""
let start = Date()
resultOutput.text = source.utf8.lazy.map {self.byteToBinaryString(byte: $0)}
.joined()
let end = Date()
print(end.timeIntervalSince(start))
}
private func byteToBinaryString(byte:UInt8) -> String {
var result = String(byte, radix: 2)
if result.count < 8 {
result += String(repeating: "0", count: 8 - result.count)
}
return result;
}


DispatchQueue is not an accelerator. If it is wrongly used, it does not help improving responses of your app.


660 characters to encode should be nothing for an iPhone, if correctly coded…

I don't understand what you do in btnEncode if > 100.

You first
encodeBinaryWhenCharOverlimit(input: source)
then encode again
                self.encodeStringBinary(string: source); return
What is source ?

Why sleep(1) ?
Accepted Answer
Simply and frankly speaking, your code is full of inefficient operations and mis-usages of DispatchQueue.

On my machine, a little bit more efficient code takes 7 msec to convert 660 ASCII characters.
You may not want to use DispatchQueue for this short period of freezing.
Code Block
@IBAction func btnEncode(_ sender: Any) {
let source = sourceString.text ?? ""
let start = Date()
resultOutput.text = source.utf8.lazy.map {self.byteToBinaryString(byte: $0)}
.joined()
let end = Date()
print(end.timeIntervalSince(start))
}
private func byteToBinaryString(byte:UInt8) -> String {
var result = String(byte, radix: 2)
if result.count < 8 {
result += String(repeating: "0", count: 8 - result.count)
}
return result;
}


DispatchQueue is not an accelerator. If it is wrongly used, it does not help improving responses of your app.


iOS UI freezes up on heavy "String to Binary" conversions
 
 
Q