Extracting string values from this json in IOS swift - ios

I am using swiftyjson to extract the json but i cant able to extract specification json that is label and value inside specification. I need it quickly.
((
{
code = "NPR 1515";
description = "With its enhanced power and performance the NPR1515 provides a genuine \"workhorse\" that will take almost anything in its stride.
\nThe full 1500 Watt motor unit packs almost 50% more power than normally required and this power is transmitted to the floor through our long established 150rpm, oil filled, low load, planetary gearbox .
\nThe big advantage of excess power is to provide scope for many additional tasks where the excess power is both advantageous and needed.";
id = 16;
name = "Scrubbers & Polisher - NPR 1515";
specification = "[{\"label\":\"Model No\",\"value\":\"PR 1515\\t\\t\\r\"},{\"label\":\"\\nMotor\",\"value\":\"500W\\t\\r\"},{\"label\":\"\\nPad\",\"value\":\"00mm\\t\\r\"},{\"label\":\"\\nPower\",\"value\":\"30V AC 50Hz\\r\"},{\"label\":\"\\nBrush\",\"value\":\"50mm\\t\\r\"},{\"label\":\"\\nSpeed\",\"value\":\"50 rpm\\r\"},{\"label\":\"\\nVacuum\",\"value\":\"T130\\t\\r\"},{\"label\":\"\\nRange\",\"value\":\"2m\\t\\t\\r\"},{\"label\":\"\\nWeight\",\"value\":\"0 Kgs\\t\\r\"},{\"label\":\"\\nSize\",\"value\":\"185 x 580x 450mm\"}]";
"video_url" = "<null>";
}
))
let json2 = JSON(data3!)
for (index, object) in json2 {
let name = object["name"].stringValue
let code = object["code"].stringValue
let description = object["description"].stringValue
let specification = object["specification"].stringValue
does not run this part.
let json3 = JSON(specification)
for (index, object3) in json3 {
println("in this loop")
if let specification2 = object3["label"].string {
println(specification2)
}
else {
println(object3["label"].error)
}
let specification3 = object3["value"].stringValue
println(specification3)
}
ok now it is working but label are not able to print in label they are working in println but if i do this value works but not label.
let str = self.labelArray[i]
let label8 = UILabel(frame: CGRectMake(2, 0, 0, 0))
label8.backgroundColor = UIColor.whiteColor()
label8.textColor = UIColor.blackColor().colorWithAlphaComponent(0.7)
label8.frame = CGRect(x: 10, y: setheight , width: screenWidth/2, height: 25)
label8.textAlignment = NSTextAlignment.Left
label8.text = str
self.scrollview_add.addSubview(label8)
var label7 = UILabel(frame: CGRectMake(2, 0, 0, 0))
label7.backgroundColor = UIColor.whiteColor()
label7.textColor = UIColor.blackColor().colorWithAlphaComponent(0.7)
label7.frame = CGRect(x: screenWidth/2, y: setheight , width: screenWidth/2, height: 25)
label7.textAlignment = NSTextAlignment.Right
label7.text = self.valueArray[i]
self.scrollview_add.addSubview(label7)
setheight += 25

As posted in your question value of specification is a string so first you have to convert it into NSData then convert it into json:
if let jsonData = specification.dataUsingEncoding(NSUTF8StringEncoding){
let json = JSON(data:jsonData)
for (index, object3) in json {
println("in this loop")
if let specification2 = object3["label"].string {
println(specification2)
}
else {
println(object3["label"].error)
}
let specification3 = object3["value"].stringValue
println(specification3)
}
}

According to the data structure you posted, the value inside "specification" is a string, not a JSON object. There're two ways to do it properly:
1, format the JSON data correctly, i.e, instead of a string, the "specification" should also be a JSON object (array with dictionaries), depending on where you get this JSON data, you need to modify the generation logic of this data to accomplish this.
2, you can manually parse the specification using JSON parser, for example:
let error: NSErrorPointer = nil;
let specificationString = "[{\"label\":\"Model No\",\"value\":\"PR 1515\\t\\t\\r\"},{\"label\":\"\\nMotor\",\"value\":\"500W\\t\\r\"},{\"label\":\"\\nPad\",\"value\":\"00mm\\t\\r\"},{\"label\":\"\\nPower\",\"value\":\"30V AC 50Hz\\r\"},{\"label\":\"\\nBrush\",\"value\":\"50mm\\t\\r\"},{\"label\":\"\\nSpeed\",\"value\":\"50 rpm\\r\"},{\"label\":\"\\nVacuum\",\"value\":\"T130\\t\\r\"},{\"label\":\"\\nRange\",\"value\":\"2m\\t\\t\\r\"},{\"label\":\"\\nWeight\",\"value\":\"0 Kgs\\t\\r\"},{\"label\":\"\\nSize\",\"value\":\"185 x 580x 450mm\"}]"
if let specificationData = specificationString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) {
let specificationObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(specificationData, options: .MutableContainers, error: error)
//Now you have a correct Array, do whatever you want with it.
}

Related

How to Convert GMUFeature to GMSPath

I have drawn slots on google maps using Geojson. Now when the user long presses on the slot should ask the user whether to save the location or not. But I don't know how to enable long press only for the slots. Could anybody suggest me how to do this. Below is the code I have used.
`// the below is the code to render the slots on the google maps
let geoJsonParser = GMUGeoJSONParser(url: url!)
geoJsonParser.parse()
let renderer = GMUGeometryRenderer(map: self.mapview, geometries: geoJsonParser.features)
let style = GMUStyle(styleID: "random", stroke: UIColor.black, fill: UIColor.green, width: 2, scale: 1, heading: 0, anchor: CGPoint(x: 0, y: 0), iconUrl: nil, title: nil, hasFill: true, hasStroke: true)
for feature in geoJsonParser.features {
feature.style = style
}
renderer.render()
// The below code is to check whether the user has long pressed on the slot or not(written this code inside the didLongPressAt function).
for feature in geoJsonParser.features {
if GMSGeometryContainsLocation(coordinate, feature as! GMSPath, true) {// the app is crashing with an error in the console "Could not cast value of type 'GMUFeature' (0x1033573d0) to 'GMSPath' (0x1033585a0)"
print("YES: you are in this polygon.")
marker.title = "\(coordinate)"
marker.map = mapview
} else {
print("You do not appear to be in this polygon.")
}
}`
Finally, after lot of efforts I found the solution.
Note: If anyone is integrating Google-Maps-iOS-Utils library, then don't add header files in Bridging-Header file as suggested in Google developer document.
Wherever you are using the below code, just write import GoogleMapsUtils at top.
let path = Bundle.main.path(forResource: "dld_areas", ofType: "json")
let url = URL(fileURLWithPath: path!)
let data: Data = try! Data.init(contentsOf: url)
let json = try JSON(data: data)
//our json is having properties containing area name and area id, bacause the properties field inside the GMUFeature is retuning us nil, we have to pass it indiviually
let jsonFeatures: [JSON] = json["features"].array ?? []
geoJsonParser = GMUGeoJSONParser.init(data: data)
geoJsonParser.parse()
var index = 0
for feature in geoJsonParser.features {
var innerFeature = feature
while(innerFeature.geometry.type != "GeometryCollection"){
print("type is" + innerFeature.geometry.type)
innerFeature = innerFeature.geometry as! GMUGeometryContainer
}
let collection = innerFeature.geometry as! GMUGeometryCollection
let polygon:GMUPolygon = collection.geometries.first as! GMUPolygon
var isAreaObtained = false
for path in polygon.paths{
//check if the coordinates lie within the polygon
if (GMSGeometryContainsLocation(coordinates, path, true)) {
isAreaObtained = true
print(jsonFeatures[index]["properties"]["NAME_EN"])
print(jsonFeatures[index]["properties"]["AREA_ID"])
print("location inside polygon")
break;
}
}
if(isAreaObtained){
break
}
index = index + 1
}
I found the above code in the following link:
https://github.com/googlemaps/google-maps-ios-utils/issues/205
I have used this code and modified as per my requirement.

How to show json data in line chart using swift

I am trying to design an ios app to display json data in a line chart.
First of all, this is my json data.
{
TH_5min: [
{
Data: "2019-02-23T00:00:00",
Time: "11:00:00",
XTP_A: 10.5, //temperature 1
XHP_A: 11.5, //humidity 1
XTP_B: 33.5,
XHP_B: 44.6,
XTP_C: 88.9,
XHP_C: 66.6,
XTP_D: 77.9,
XHP_D: 99.6,
XTP_E: 87.87,
XHP_E: 66.66
},
{
Data: "2019-02-23T00:00:00",
Time: "11:05:00",
XTP_A: 55.2, //temperature 1
XHP_A: 44.3, //humidity 1
XTP_B: 66.6,
XHP_B: 77.87,
XTP_C: 87.77,
XHP_C: 87.87,
XTP_D: 8.87,
XHP_D: 78.78,
XTP_E: 87.78,
XHP_E: 87.87
}
]
}
This is my implementation of the swift code showing json data.
override func viewDidLoad() {
super.viewDidLoad()
apiip = APIip
getlatestTh_5min()
#objc func getlatestTh_5min(){
guard let th_5minUrl = URL(string: "http://" + apiip + "/api/Th_5min") else{
return
}
let request = URLRequest(url: th_5minUrl)
let task = URLSession.shared.dataTask(with: request, completionHandler: {(data,response,error) -> Void in
if let error = error {
print(error)
return
}
if let data = data {
self.th_5mins = self.pardrJsonData(data: data)
self.getchat()
}
})
task.resume()
//getchat()
}
func pardrJsonData(data: Data) -> [Th_5min]{
var th_5mins = [Th_5min]()
do {
let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
let jsonTh_5mins = jsonResult?["TH_5min"] as! [AnyObject]
print(jsonTh_5mins)
print(th_5mins.count)
for jsonTh_5min in jsonTh_5mins{
var th_5min = Th_5min()
th_5min.Data = jsonTh_5min["Data"] as! String
th_5min.Time = jsonTh_5min["Time"] as! String
th_5min.XTP_A = jsonTh_5min["XTP_A"] as! Double
th_5min.XHP_A = jsonTh_5min["XHP_A"] as! Double
print(th_5min)
th_5mins.append(th_5min)
//getchat()
} }catch{
print(error)
}
//getchat()
return th_5mins
}
This is how I draw the line chart, using swift code.
#objc func getchat(){
chartView = LineChartView()
chartView.frame = CGRect(x: 20, y: 80, width: self.view.bounds.width-20,height: self.view.bounds.height-100)
self.view.addSubview(chartView)
var dataEntries1 = [ChartDataEntry]()
for i in 0..<th_5mins.count {
chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: [th_5mins[i].Time])
let y = th_5mins[i].XTP_A
let entry = ChartDataEntry.init(x: Double(i), y: Double(y))
dataEntries1.append(entry)
}
let chartDataSet1 = LineChartDataSet(entries: dataEntries1, label: "temperature")
chartDataSet1.colors = [NSUIColor.red]
var dataEntries2 = [ChartDataEntry]()
for i in 0..<th_5mins.count {
chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: [th_5mins[i].Time])
let y = th_5mins[i].XHP_A
let entry = ChartDataEntry.init(x: Double(i), y: Double(y))
dataEntries2.append(entry)
}
let chartDataSet2 = LineChartDataSet(entries: dataEntries2, label: "humidity")
chartDataSet2.colors = [NSUIColor.black]
let chartData = LineChartData(dataSets: [chartDataSet1, chartDataSet2])
chartView.data = chartData
}
}
This is the result of my work.
enter image description here
Although the json data is successfully displayed, I don't know why it is loading for a long time, and I hope that the "time" in my json data can be displayed on the X axis above, marked with my temperature and humidity, and cannot be successful.
I also hope that my line chart view can be implemented as a layout.
"I don't know why it is loading for a long time". Do you mean that the graph does not load immediately upon opening the view? This is because the data is loading asynchronously from a remote source (correctly now, well done). It may well take a few seconds for your JSON to download over the web. That is ok. You can test the endpoint in a browser and see how long the response takes.
"I hope that the 'time' in my json data can be displayed on the X axis above". Yes. You can take the assignation of IndexAxisValueFormatter outside of the loop and you should pass all labels as values into the constructor. Try this code, replacing the equivalent loop:-
var labels: [String] = []
for i in 0..<th_5mins.count {
let y = th_5mins[i].XTP_A
let entry = ChartDataEntry.init(x: Double(i), y: Double(y))
dataEntries1.append(entry)
labels.append(th_5mins[i].Time)
}
chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: labels)
Note that the method you use for plotting against dates will result in an evenly spread graph, irrespective of your time gaps (e.g. if readings are 5 mins apart between the first two, but 5 years apart for the next two, they will still appear with even gaps between them.

Developing an ARKit app that leaves text for others to view

I am creating an iOS AR app that sets text in a specific location and leaves it there for others to view. Is there a better way to implement it than what I am doing?
Currently, I have it set so that the text is saved to Firebase and loads it by setting the nodes relative to the camera’s position. I’m wondering if there is a way to save ARAnchors in a fashion similar to what I am doing but is that possible?
My current function for saving the text to the location via a user tapping the screen:
/*
* Variables for saving the user touch
*/
var touchX : Float = 0.0
var touchY : Float = 0.0
var touchZ : Float = 0.0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// will be used for getting the text
let textNode = SCNNode()
var writing = SCNText()
// gets the user’s touch upon tapping the screen
guard let touch = touches.first else {return}
let result = sceneView.hitTest(touch.location(in: sceneView), types: [ARHitTestResult.ResultType.featurePoint])
guard let hitResult = result.last else {return}
let hitTransform = SCNMatrix4.init(hitResult.worldTransform)
let hitVector = SCNVector3Make(hitTransform.m41, hitTransform.m42, hitTransform.m43)
// saves X, Y, and Z coordinates of touch relative to the camera
touchX = hitTransform.m41
touchY = hitTransform.m42
touchZ = hitTransform.m43
// Was thinking of adding the ability to change colors. Probably can skip next seven lines
var colorArray = [UIColor]()
colorArray.append(UIColor.red)
writing = SCNText(string: input.text, extrusionDepth: 1)
material.diffuse.contents = colorArray[0]
writing.materials = [material]
// modifies the node’s position and size
textNode.scale = SCNVector3(0.01, 0.01, 0.01)
textNode.geometry = writing
textNode.position = hitVector
sceneView.scene.rootNode.addChildNode(textNode)
// last few lines save the info to Firebase
let values = ["X" : touchX, "Y" : touchY, "Z" : touchZ, "Text" : input.text!] as [String : Any]
let childKey = reference.child("Test").childByAutoId().key
if input.text != nil && input.text != "" {
let child = reference.child("Test").child(childKey!)
child.updateChildValues(values)
} else {
let child = reference.child("Test").child(childKey!)
child.updateChildValues(values)
} // if
} // override func
/*
* Similar to the previous function but used in next function
*/
func placeNode(x: Float, y: Float, z: Float, text: String) -> Void {
let textNode = SCNNode()
var writing = SCNText()
let hitVector = SCNVector3Make(x, y, z)
touchX = x
touchY = y
touchZ = z
var colorArray = [UIColor]()
colorArray.append(UIColor.red)
writing = SCNText(string: text, extrusionDepth: 1)
material.diffuse.contents = colorArray[0]
writing.materials = [material]
textNode.scale = SCNVector3(0.01, 0.01, 0.01)
textNode.geometry = writing
textNode.position = hitVector
sceneView.scene.rootNode.addChildNode(textNode)
} // func
/*
* This next function is used in my viewDidLoad to load the data
*/
func handleData() {
reference.child("Test").observeSingleEvent(of: .value, with: { (snapshot) in
if let result = snapshot.children.allObjects as? [DataSnapshot] {
for child in result {
let xCoord = Float(truncating: child.childSnapshot(forPath: "X").value as! NSNumber)
let yCoord = Float(truncating: child.childSnapshot(forPath: "Y").value as! NSNumber)
let zCoord = Float(truncating: child.childSnapshot(forPath: "Z").value as! NSNumber)
let inscription = child.childSnapshot(forPath: "Text").value
self.placeNode(x: xCoord , y: yCoord , z: zCoord , text: inscription as! String)
} // for
} // if
}) // reference
} // func
I have looked into a few things such as ARCore but that looks like it uses Objective-C. I’ve made this app in Swift and I am not sure if I can incorporate ARCore with how I have implemented my current application.
Do I just need to get over it and learn Objective-C? Can I still work with what I have?
I think that ARCore anchors are only available for 24 hours, so that could be a problem.
You probably need to use ARKit2.0's ARWorldMap and save it as data on firebase for others to see the text in the same place, otherwise you are assuming in your code that future users will start their AR session in the exact same position and direction as the person who left the text. You probably need to use core location first to see where in the world the user is.

textLabel.text in UIViewController comes up nil while assigning string from NSObject

I'm an iOS and programming noob so I apologize for any bad phrasing or mistakes.
I'm parsing quotes from an API for my app which displays it on a textLabel each time a UIButton is clicked. In order to keep the string from going off the textLabel or be resized to an unreadable font, I'm trying to request a new quote if the string character count is too high by calling a function in my NSObject. I set up a NSObject to do the refetching but whenever I try to reassign the the string to the textLabel.text from the NSObject or try to send the string back to the ViewController the qouteLabel.text comes back nil
Here is my viewcontroller where I'm making the initial request for the quote
import UIKit
import Alamofire
class RSQuotesViewController: RSViewController {
var ronImageView: UIImageView!
var quoteLabel = UILabel!()
override func loadView() {
let frame = UIScreen.mainScreen().bounds
let view = UIView(frame: frame)
view.backgroundColor = UIColor.grayColor()
ronImageView = UIImageView(frame: CGRectMake(frame.width/2-160, frame.height-600, 320, 600))
let ron = "ron.png"
let ronImage = UIImage(named: ron)
ronImageView.image = ronImage
view.addSubview(ronImageView);
let labelWidth = ronImageView.frame.width/2
let quoteLabelX = labelWidth-40
quoteLabel = UILabel(frame: CGRect(x: quoteLabelX, y: ronImageView.frame.height/4+15, width: labelWidth, height: 160))
quoteLabel.textAlignment = .Center
quoteLabel.text = "Click to Start"
quoteLabel.shadowColor = UIColor.grayColor()
quoteLabel.adjustsFontSizeToFitWidth = true
quoteLabel.lineBreakMode = .ByWordWrapping // or NSLineBreakMode.ByWordWrapping
quoteLabel.numberOfLines = 0
view.addSubview(quoteLabel)
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
let frame = UIScreen.mainScreen().bounds
let getQuote = UIButton(frame: CGRect(x: 0, y: 0, width: frame.size.width+50, height: frame.size.height))
getQuote.backgroundColor = UIColor.clearColor()
getQuote.setTitle("", forState: UIControlState.Normal)
getQuote.addTarget(self, action: #selector(RSQuotesViewController.getQuote(_:)), forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(getQuote)
}
// Gets quote when button is pressed
func getQuote(sender: UIButton){
let url = "http://ron-swanson-quotes.herokuapp.com/v2/quotes"
Alamofire.request(.GET, url, parameters: nil).responseJSON { response in
if let JSON = response.result.value as? Array<String>{
let quoteDict = RSQoute()
// if quote is too large get another one
if (JSON[0].characters.count > 120){
print("greater than 120")
quoteDict.fetchQuote()
} else {
self.quoteLabel.text = JSON[0]
}
}
}
}
This is my model where I'm trying to reassign the quoteLabel.text and getting nil
import UIKit
import Alamofire
class RSQoute: NSObject {
var newQuote = String()
// fetchs new quote if quote is too large
func fetchQuote(){
let url = "http://ron-swanson-quotes.herokuapp.com/v2/quotes"
Alamofire.request(.GET, url, parameters: nil).responseJSON { response in
if let JSON = response.result.value as? Array<String>{
self.newQuote = JSON[0]
if (self.newQuote.characters.count > 120) {
print("Try Again: ---->\(self.newQuote)")
return self.fetchQuote()
} else {
let quoteVC = RSQuotesViewController()
print("Retry was less than 120: ---->\(self.newQuote)")
print("quoteLabelText: ---->\(RSQuotesViewController().quoteLabel.text)")// comes back nil
RSQuotesViewController().quoteLabel.text = self.newQuote
}
}
}
}
}
Please let me know if there something I'm missing or an easier/better way of trying to fetch a new quote from the API :)
In your function fetchQuote(), you set quoteVC as a new instantiation of RSQuotesViewController() with let quoteVC = RSQuotesViewController(). Instead you should be setting the quoteLabel.text for the applications instance of RSQuotesViewController(). You are also making two API requests. Once inside the fetchQuote() function for RSQuotesViewController and once inside your fetchQuote() function for RSQuotes
I think what you are looking for would involve closures. Try this out for your fetchQuote() function in your RSQuotes class
func fetchQuote(completion: (result:String)){
let url = "http://ron-swanson-quotes.herokuapp.com/v2/quotes"
Alamofire.request(.GET, url, parameters: nil).responseJSON { response in
if let JSON = response.result.value as? Array<String>{
self.newQuote = JSON[0]
if (self.newQuote.characters.count > 120) {
print("Try Again: ---->\(self.newQuote)")
completion(result: self.newQuote)
} else {
print("Retry was less than 120: ---->\(self.newQuote)")
print("quoteLabelText: ---->\(RSQuotesViewController().quoteLabel.text)")// comes back nil
completion(result: self.newQuote)
}
}
Then, I would have a setQuote function RSQuotesViewController where you could just do something like this
func setQuote() {
let quoteObj = RSQuote()
quoteObj.fetchQuote() {
result in
quoteLabel.text = result
}
}
I would take a look at some posts related to swift closures and also check out. http://goshdarnclosuresyntax.com/
On a side note, I'm not sure if you were planning to manipulate the quoteString within your RSQuote class. If not, it might be better for fetchQuote() to be a static func. This way you can just call it without initializing the object in RSQuoteViewController. It'd be something like RSQuote.fetchQuote()

Parse a string of 4 numbers into a CGRect [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have this string (325, 140, 739, 979) . I want to parse it and take the four numbers separately.
This string represents a CGRect. I want to take the first number as x the second as y the third as width and the last as height.
What is the best way to achieve this ?
Given your string, you can fetch the numbers as an array of optional Int like this:
let str = "(325, 140, 739, 979)"
let nums = split(str) { contains("(), ", $0) }.map { $0.toInt() }
That split will remove any of the characters in the string passed to contains. You now have an array of optionals, which you can check for the correct contents:
let rect: CGRect
if nums.count == 4,
let x = nums[0], y = nums[1],
w = nums[2], h = nums[3]
{
rect = CGRect(x: x, y: y, width: w, height: h)
}
else {
// report an error, or default the values if you prefer
fatalError("Malformed input string")
}
Any extraneous characters in your input string will result in nil for one of the integers, or the wrong count in the array, so this should be safe against any garbage input.
For convenience, you could put all this in a failable initializer for CGRect:
extension CGRect {
init?(string: String) {
// note, since CGRect also has a contains method, need to specify Swift.contains
let nums = split(string) { Swift.contains("(), ", $0) }.map { $0.toInt() }
if nums.count == 4,
let x = nums[0], y = nums[1],
w = nums[2], h = nums[3]
{
self = CGRect(x: x, y: y, width: w, height: h)
}
else {
return nil
}
}
}
let rectangles = [
"(325, -140, 739, 979)", // valid
"(1,2,3,asdadaf)", // invalid (non-integer)
"1,2,3,4,", // valid
"(1,2,3,4,5)", // invalid (wrong count)
]
// returns an array of 2 valid CGRect and 2 nil
let cgrects = rectangles.map { CGRect(string: $0) }
Obviously there’s lots you could tweak here if you wanted to be more or less permissive in terms of the kind of input you’re willing to convert.
Here is my solution for your case:
func parse(str : String) -> [Int] {
var firstStepStr = str.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "()")) //remove ( and )
var secondStepArray = firstStepStr.componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: ", ")).filter{$0 != ""} //separated by , and ignore ""
return secondStepArray.map{$0.toInt() ?? 0} //convert to [Int], if cannot convert to Int, return 0
}
let cgrectString = "(325, 140, 739, 979)"
let intArray = parse(cgrectString)
First, we could get rid of the parentheses
let myString = "(325, 140, 739, 979)"
let myReplacementString = String(map(myString.generate()) {
$0 == "(" || $0 == ")" ? "-" : $0
})
You could also take a substring, which doesn't seem to be any nicer.
Then we could split the string into array
var myArray = myReplacementString.componentsSeparatedByString(", ")
And then use a loop to cast string to int
for item in myArray {
item.toInt()
}
or just use myArray[i].toInt() to give them straight to constructor etc.
This will get you an array of the four CGFloat values you are looking for:
func stringToCGFloatArray(string: String) -> [CGFloat] {
return string.componentsSeparatedByCharactersInSet(
NSCharacterSet(charactersInString: "(), ")).reduce([CGFloat]()) {
if let x = $1.toInt() {
return $0 + [CGFloat(x)]
} else {
return $0
}
}
}
You can then convert it to an optional tuple that can be provided directly to CGMakeRect:
func arrayToRectParameters(array: [CGFloat]) -> (CGFloat, CGFloat, CGFloat, CGFloat)? {
switch array.count {
case 4:
return (array[0], array[1], array[2], array[3])
default:
return nil
}
}
Now you can create a CGRect like this:
let str = "(325, 140, 739, 979)"
if let rectParameters = arrayToRectParameters(stringToCGFloatArray(str)) {
let myCGRect = CGRectMake(rectParameters)
println(myCGRect) // prints (325.0,140.0,739.0,979.0)
}

Resources