Parse unicode character from server, iOS Swift - ios

I use a paid set of linear icon's from this website.
It's great! Especially in iOS I put the .ttf file in my projects bundle, load the font and use it in labels and buttons. I even wrote an article about how I do this.
My problem comes when I want to dynamically change a label based on some server value. My initial instinct was to save the unicode value as text up on the server. I simply save the the value such as ed02 and when I pull it down into my App I add it to, let's say, a label like this.
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
label.font = IconUltimate().icoUltimateFont(18)
let valueFromServer = "ed02"
label.text = "\u{\(valueFromServer)}"
The problem is that the line:
label.text = "\u{\(valueFromServer)}"
is invalid. What am I doing wrong? Is there a way to inject a unicode value from the server into my UI? My solution right now is to map the unicode value from the server using a switch statement like this:
public func unicodeMapper(rawUnicode: String) -> String {
switch rawUnicode {
case "ecf5":
let thumbs_up = "\u{ecf5}"
return thumbs_up
default:
return ""
}
}
And call it like this:
let valueFromServer = "ed02"
label.text = unicodeMapper(rawUnicode: valueFromServer)
Anyone have any suggestions so I don't have to use a switch statement and I can just inject the value from the server?
Thanks

Like this:
let code = "ecf5" // or whatever you got from the server
let codeint = UInt32(code, radix: 16)!
let c = UnicodeScalar(codeint)!
label.text = String(c)

Related

SwiftUI:! [Array] the compiler is unable to type-check this expression in reasonable time

Can you help me solve this problem?
The problem is in the second button with the string array inside the Text Code, if there is an string array inside the text code mark the typical error: "the compiler is unable to type-check this expression in reasonable time", but if I change the string array to a normal string, there is no error.
The second button just appears if the sti array has 2 or more elements inside it with the second element.
Group {
let telephone = "tel://"
Button(action:{
let formattedString = telephone + CardPn[0]
guard let url = URL(string: formattedString) else { return }
UIApplication.shared.open(url)
}){
Text(CardPn[0])
.fontWeight(.bold)
.underline()
}
if CardPn.count >= 2{
Button(action:{
let formattedString = telephone + CardPn[1]
guard let url = URL(string: formattedString) else { return }
UIApplication.shared.open(url)
}){
Text(CardPn[1])
.fontWeight(.bold)
.underline()
}
}
}
General advice to fix the-compiler-is-unable-to-type-check-this-expression-in-reasonable-time errors:
Use explicit types for your variables:
let telephone = "tel://" // Not Optimal
let telephone: String = "tel://" // This is Better because of the explicit `: String`
Use smaller declarations instead of a one big thing that contains all your logic:
var body: some View {
// Not optimal button
Button(action: {
// do something
.
.
.
}, label: {
Text("something")
.
.
.
})
// Better example of a button
Button(action: actionOfTheButton, label: buttonLabel)
}
// Declare the action somewhere else
func actionOfTheButton() {
// do something
.
.
.
}
// Label of the button is declared here
var buttonLabel: some View {
Text("something")
.
.
.
}
Avoid big calculations in one variable:
// We want to calculate the finalArea
// some variables to showcase
let someWidth: CGFloat = 200
let someHeight: CGFloat = 450
let ratio: CGFloat = 0.75
let maxSize: CGFloat = 80000
let minSize: CGFloat = 100
// not optimal because there are lots calculations going on in one line
// to calculate the finalArea
let finalArea = max(min((someWidth * someHeight) * ratio, minSize), maxSize)
// this approach is better, both for compiler and for code-readability,
// finalArea is calculated in 3 steps instead of 1:
let initialArea = someWidth * someHeight
let areaWithRatio = initialArea * ratio
let finalArea = max(min(areaWithRatio, minSize), maxSize)
Make sure you don't have something too big. e.g. an array containing 5000 lines of Elements will likely make the compiler complain.
The last possibility i remember, is that you have a syntax error or other errors on your side.
In this case you should just try to eye-ball the problem and fix it.
You don't need to go all-in in declaring explicit types, as thats one of the nice features of the Swift language and you don't want to be throwing that away, but as a matter of fact, that always helps the compiler.
About the second tip, it is generally advised to cut your app to smaller components instead of big components. That also helps your code to be better readable and more manageable. The bigger your project, the more you thank yourself for these smaller components.

Change Array of Int to String so it can be put into a label.text

I have an array:
var numberArray = [1,2,3]
I want to convert this into a string and put it into a label text:
label.text = "123"
I've already tried for loops / other things online. Thanks :)
You can simply do this using higher order functions Map and Reduce
label.text = numberArray.map{ String($0) }.reduce("", +)
Or you can use joined() as well
label.text = numberArray.map{String($0)}.joined()
You can also use map this way
label.text = numberArray.map(String.init).joined()

Getting string from label visible at runtime

I want to get the string which is visible at my label and having line break mode .byClipping .
My real string is :-
"This way your API interface will be nice and pretty, you’re not exposing the internals of your class to the world. If you have constants that are used in lots of classes all over the app then it makes sense to have a separate .h and .m file just for defining these constants."
but at run time i am getting :-
"This way your API interface will be nice and pretty, you’re not exposing the internals of your class to the world. If you have constants"
i want to get the below string in a variable at runtime.
I am not sure if this is natively doable. The closest idea I have is to test the string size and removing/adding characters. Check if the following works for you:
func findTextActuallyVisibleInLabel(_ label: UILabel) -> String? {
guard let originalText = label.text else { return nil }
var text = originalText
let labelSize = label.bounds
guard labelSize.height > 0 else { return text }
let bounds: CGRect = CGRect(x: 0.0, y: 0.0, width: labelSize.width, height: CGFloat.infinity)
while !text.isEmpty && label.textRect(forBounds: bounds, limitedToNumberOfLines: label.numberOfLines).height > labelSize.height {
text.removeLast()
label.text = text
}
label.text = originalText
return text
}
This seems to do its job in my case more or less. If I use wrapping that ends text with ... the result is incorrect.
Also some optimization may be nice; currently I just use the full string and start subtracting character by character. Maybe a bisection would be nicer here.
I do still use original label so it should take all possible parameters into account like wrapping, font size, lines... I modify the actual text on the label which is then reset to original.
Possibly view animations should be disabled while this operation is in progress.

Swift: Display (LaTeX) math expressions inline

I would like to display math terms inside a text, in particular in an inline mode, i.e. inside a sentence.
Using LaTeX, this would for example look like:
"Given a right triangle having catheti of length \(a\) resp. \(b\) and a hypotenuse of length \(c\), we have
\[a^2 + b^2 = c^2.\]
This fact is known as the Pythagorean theorem."
Does anybody know how this can be achieved in Swift?
(I know that this example may be achieved in Swift without LaTeX-like tools. However, the expressions in my mind are in fact more complex than in this example, I do need the power of LaTeX.)
The optimal way would be a UITextView-like class which recognizes the math delimiters \(,\) resp. \[,\], recognizes LaTeX code inside these delimiters, and formats the text accordingly.
In the Khan Academy app, this problem seems to be solved as the screenshots in the Apple App Store/Google Play Store show inline (LaTeX) math.
I’ve found the package iosMath which provides a UILabel-like class MTMathUILabel. As this class can display solely formulas, this seems to be not good enough for my purpose, except if there was a method which takes a LaTeX source text such as in the example above, formats expressions such as \(a\) into tiny MTMathUILabels and sets these labels between the other text components. As I am new to Swift, I do not know whether and how this can be achieved. Moreover, this seems to be very difficult from a typographical point of view as there will surely occur difficulties with line breaks. And there might occur performance issues if there are a large number of such labels on the screen at the same time?
It is possible to achieve what I want using a WKWebView and MathJax or KaTeX, which is also a hack, of course. This leads to other difficulties, e.g. if one wants to set several of these WKWebViews on a screen, e.g. inside UITableViewCells.
Using iosMath, my solution on how to get a UILabel to have inline LaTeX is to include LATEX and ENDLATEX markers with no space. I replaced all ranges with an image of the MTMathUILabel, going from last range to first range so the positions don't get screwed up (This solution allows for multiple markers). The image returned from my function is flipped so i used .downMirrored orientation, and i sized it to fit my text, so you might need to fix the numbers a little for the flip scale of 2.5 and the y value for the attachment.bounds.
import UIKit
import iosMath
let question = UILabel()
let currentQuestion = "Given a right triangle having catheti of length LATEX(a)ENDLATEX resp. LATEX(b)ENDLATEX and a hypotenuse of length LATEX(c)ENDLATEX, we have LATEX[a^2 + b^2 = c^2]ENDLATEX. This fact is known as the Pythagorean theorem."
question.text = currentQuestion
if (question.text?.contains("LATEX"))! {
let tempString = question.text!
let tempMutableString = NSMutableAttributedString(string: tempString)
let pattern = NSRegularExpression.escapedPattern(for: "LATEX")
let regex = try? NSRegularExpression(pattern: pattern, options: [])
if let matches = regex?.matches(in: tempString, options: [], range: NSRange(location: 0, length: tempString.count)) {
var i = 0
while i < matches.count {
let range1 = matches.reversed()[i+1].range
let range2 = matches.reversed()[i].range
let finalDistance = range2.location - range1.location + 5
let finalRange = NSRange(location: range1.location, length: finalDistance)
let startIndex = String.Index(utf16Offset: range1.location + 5, in: tempString)
let endIndex = String.Index(utf16Offset: range2.location - 3, in: tempString)
let substring = String(tempString[startIndex..<endIndex])
var image = UIImage()
image = imageWithLabel(string: substring)
let flip = UIImage(cgImage: image.cgImage!, scale: 2.5, orientation: .downMirrored)
let attachment = NSTextAttachment()
attachment.image = flip
attachment.bounds = CGRect(x: 0, y: -flip.size.height/2 + 10, width: flip.size.width, height: flip.size.height)
let replacement = NSAttributedString(attachment: attachment)
tempMutableString.replaceCharacters(in: finalRange, with: replacement)
question.attributedText = tempMutableString
i += 2
}
}
}
func imageWithLabel(string: String) -> UIImage {
let label = MTMathUILabel()
label.latex = string
label.sizeToFit()
UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0)
defer { UIGraphicsEndImageContext() }
label.layer.render(in: UIGraphicsGetCurrentContext()!)
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}

Using variables in CGRectMake, Swift, UIkit

For an App I'm making i need to use variables to change the size and position of objects (Labels). I've tried var example = CGRectMake(0, 0, 0, 100), hoping it would ignore the zeros (Not really thinking it would though). I then tried:
var example = 100
Label1.frame = CGRectMake(20, 20, 50, example)
I changed the syntax a bit, adding "" and replacing the CGRectMake with CGRect etc, but nothing worked... I don't get what I'm doing wrong here... Help!
Below is the new syntax used since Swift 3.
CGRect(x: 0, y: 0, width: 100, height: 100)
CGRectMake takes CGFloats for all of its arguments. Your sample code should work fine if you specify that example is supposed to be a CGFloat, using a type identifier:
// v~~~~ add this...
var example: CGFloat = 100
Label1.frame = CGRectMake(20, 20, 50, example)
Otherwise, swift infers the type of example to be Int, and the call to CGRectMake fails, cuz it can't take an Int as a parameter...
So, there is many ways to skin the cat. It all depends what your needs and requirements are (maybe you could elaborate a bit on what you are trying to achieve?). But one way to do it could be to set a variable when something happens, and then update the frame of the label. If you added a tap gesture recognizer to your view, and updated your label like so:
let myLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
let tapGestRecog = UITapGestureRecognizer(target: self, action: "handleTap:")
self.view.addGestureRecognizer(tapGestRecog)
}
func handleTap(sender:UIGestureRecognizer) {
let newXposition = sender.locationInView(self.view).x
let newYposition = sender.locationInView(self.view).y
myLabel.frame = CGRectMake(newXposition, newYposition, 200, 200)
}
This is just an example, and a very crude way of doing it. There are many other ways of doing it, but it hopefully gives you an idea of how to achieve it.
Swift allows syntax that Objective-C does not:
var example = 100
label.frame.size.height = example
In objective-C you would have to do it differently:
CGRect frame = label.frame; //Create a temporary rect to hold the frame value
frame.size.height = example;
label.frame = frame;

Resources