Use data from a scope outside of the scope - ios

I am trying to use a text from a website in an iPhone app. To do that I use a web scraper , Osmosis. I managed to retrieve the data I wanted but I can't affect the data to an array, in order to use it outside of the function. Here's a snippet of what I did:
<language: lang-swift>
class ViewController: UIViewController {
#IBOutlet weak var quote: UILabel!
private var array: [[String: AnyObject]] = []
var initArray: [[String: AnyObject]] {
get {
return array
}
set {
for e in self.initArray {
array.append(e)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
getQuotes()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getQuotes()
Osmosis(errorHandler: { (error) -> Void in
print(error)
})
.get(NSURL(string: "http://www.example.com")!)
.find(OsmosisSelector(selector: ".parentDiv"), type: .CSS)
.populate([
OsmosisPopulateKey.Single("quotes") : OsmosisSelector(selector: ".childDiv")
], type: .CSS)
.list { (dict) -> Void in
self.array.append(dict)
print(self.initArray) // this prints data
}
.start()
print(self.initArray) // This prints an empty array
}
}
I think I can't use the array because it is filled inside the init of Osmosis() but I wonder how to use it somewhere else in my code. Can you please explain what happens in my code (why can I use the data only in .list()) and how to fix that.
Edit:
I tried to use a getter and a setter in order to retrieve my data outside of the scope, but the result is the same as if there were no getter/setter.

you want to add all elements of one array to another array?
for e in quotesArray {
self.array.append(e)
}
or
self.array.appendContentsOf(quotesArray)

Based on Christian Dietrich's answer and comments, I managed to fix my issue by updating the UI inside my scope.
Here's what I did:
import UIKit
import Osmosis
class ViewController: UIViewController {
#IBOutlet weak var quote: UILabel!
var array: [[String: AnyObject]] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
getQuotes()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getQuotes() {
var updateText: String = ""
Osmosis(errorHandler: { (error) -> Void in
print(error)
})
.get(NSURL(string: "http://www.exemple.com")!)
.find(OsmosisSelector(selector: ".wrapper"), type: .CSS)
.populate([
OsmosisPopulateKey.Single("div") : OsmosisSelector(selector: ".div")
], type: .CSS)
.list { (dict) -> Void in
self.array.append(dict)
updateText = self.array[0]["div"] as! String
self.quote.text = updateText
self.view.setNeedsDisplay()
}
.start()
}
}
Thanks for your help !

Related

How to make function for HTTP request on other class in Swift?

I'm writing a app to make a http requests with SwiftHTTP, but I want to create a class to make this, and in the ViewController I call the functions to do this. So, I create a UIButton to call the functions.
I don't know if I need use threads or exists ways to make this easy.
ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self,action:#selector(self.clickRequest(sender:)), for: UIControlEvents.touchUpInside )
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func clickRequest (sender: UIButton) {
}
}
HTTPService.swift
import Foundation
import SwiftHTTP
class HTTPService {
}
How I make this in others Apps. But inside of ViewController.swift.
HTTP.GET("https://www.host.com/example",requestSerializer: JSONParameterSerializer()) {
response in
if let err = response.error {
print(err.localizedDescription)
return
}
} catch let err as NSError {
print(err)
}
}
Create one method with successBlock and failureBlock inside your HTTPService service class like below,
class HTTPService {
func makeRequest(params: [String: Any], successBlock: () -> Void, failureBlock: () -> Void) {
HTTP.GET("https://www.host.com/example",requestSerializer: JSONParameterSerializer()) {
response in
if let err = response.error {
print(err.localizedDescription)
failureBlock() // Call failure block
return
} else {
successBlock() // Call success block
}
} catch let err as NSError {
print(err)
failureBlock() // Call failure block
}
}
}
You can call this method like below,
#objc func clickRequest (sender: UIButton) {
HTTPService().makeRequest(params: ["name": "userName"], successBlock: {
// Handle API success here. E.g Reloading table view
}) {
// Handle API failure here. E.g Showing error to user
}
}
Thanks

Xcode Swift 2 Weather App problems

import UIKit
class ViewController: UIViewController {
#IBOutlet weak var cityNameTextField: UITextField!
#IBOutlet weak var cityNameLabel: UILabel!
#IBOutlet weak var cityTempLabel: UILabel!
#IBAction func getDataButtonClicked(sender: AnyObject) {
getWeatherData("http://api.openweathermap.org/data/2.5/weather?q=\(cityNameTextField.text)&APPID=6de03a1d1554874e7594a89fad719dd0")
}
override func viewDidLoad() {
super.viewDidLoad()
getWeatherData("http://api.openweathermap.org/data/2.5/weather?q=London&APPID=6de03a1d1554874e7594a89fad719dd0")
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getWeatherData(urlString: String) {
let url = NSURL(string: urlString)
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
dispatch_async(dispatch_get_main_queue(), {
self.setLabels(data!)
})
}
task.resume()
}
var jsonData: AnyObject?
func setLabels(weatherData: NSData) {
do {
self.jsonData = try NSJSONSerialization.JSONObjectWithData(weatherData, options: []) as! NSDictionary
} catch {
//error handle here
}
if let name = jsonData!["name"] as? String {
cityTempLabel.text = "\(name)"
}
if let main = jsonData!["main"] as? NSDictionary {
if let temp = main["temp"] as? Double {
cityTempLabel.text = String(format: "%.1f", temp)
}
}
}
};
Yesterday I had the app running and this morning I've just been getting new error messages that won't even allow the code to be compiled. They say 'Missing "Default-568h#2x.png" launch image' and 'Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftcode'. Thanks in advance.
You need to add something to your info.plist file:
It's because the URL link you're trying to get data from is not a secured link, so adding this to you info.plist allows you to access that link. Just go to you info.plist and right-click and select Add Row, then add exactly what you see in the image above.
Also, remove the getWeatherData function from the viewDidLoad method, as you don't need that, as you call it when you press your button.
Also, I've noticed one of your labels isn't set correctly in your setLabels function, as they both try to set the cityTempLabel label, so update the other one to be cityNameLabel.
Build and run and it should all work.

Error when I tried to read and write from Realm objects

I'm trying Realm for the first time but I'm getting errors when I tried to read and write from Realm, here is the code with the error lines commented:
class Test{
dynamic var name = ""
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var label: UILabel!
#IBAction func show(sender: UIButton){
let test = Realm().objects(Test) //cannot invoke 'objects' with no arguments
label.text = test.name
}
#IBAction func set(sender: UIButton){
let test = Test()
let realm = Realm()
test.name = "not using CoreData"
realm.write{realm.add(test)} //cannot invoke write with argument list of type (()->_)
}
}
here is the documentation page if anyone is interested: https://realm.io/docs/swift/latest/
Can you try changing you declaration of the Test class to the following?
class Test : Object

Swift - How do I update a label the Relative altitude change in iOS

I have managed to get this to print the Relative Altitude data to the log however what I would like to do is get it to print to a designated label.Any help would be appreciated.
import UIKit
import CoreMotion
class ViewController: UIViewController {
#IBOutlet weak var altitudeLabel: UILabel!
let altimeter = CMAltimeter()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func start(sender: AnyObject) {
if CMAltimeter.isRelativeAltitudeAvailable() {
altimeter.startRelativeAltitudeUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler: { data, error in
if (error == nil) {
println("relative Altitude: \(data.relativeAltitude)")
println("Pressure: \(data.pressure)")
}
})
}
}
}
You can use the following line to assign a float value with 2 decimal places to your UILabel outlet:
self.altitudeLabel.text = String(format: "%0.2f", data.relativeAltitude)
I ended up using this and it will due for now:
var myIntValue:Int = Int(data.relativeAltitude)
println ("My value is \(myIntValue)")
self.altitudeLabel.text = ("\(myIntValue) M")

Swift Barcode Scanning

I am attempting add barcode scanning to my app using RSBarcodes. I'm having two issues: Not being able to update a label that displays the barcode scanned and the delegate to send the barcode to my calling view controller not working. Below is my code for the view controller that handles the scanning:
import UIKit
import AVFoundation
import RSBarcodes
class ScanViewController: RSCodeReaderViewController {
#IBOutlet weak var label1Label: UILabel!
#IBOutlet weak var label2Label: UILabel!
#IBOutlet weak var scanLabel: UIButton!
var delegate: barcodesScannedDelegate?
var codes:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
var code=""
// Do any additional setup after loading the view.
focusMarkLayer.strokeColor = UIColor.redColor().CGColor
cornersLayer.strokeColor = UIColor.yellowColor().CGColor
tapHandler = { point in
//println(point)
}
barcodesHandler = { barcodes in
for barcode in barcodes {
if !contains(self.codes, barcode.stringValue) {
self.codes.append(barcode.stringValue)
code = barcode.stringValue
}
}
println(code)
self.label1Label.text = code
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func finishedPressed(sender: UIButton) {
delegate?.barcodesScanned(self.codes)
self.dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func cancelPressed(sender: UIButton) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Just to ensure I did the delegate correctly, here is my code in Protocol.swift:
protocol selectCarrierDelegate {
func selectCarrier(carrierID: String,carrier: String)
}
protocol barcodesScannedDelegate {
func barcodesScanned(barcodes: [String])
}
And the relevant code in the controller that should receive the barcode:
class InBoundViewController: UIViewController,selectCarrierDelegate,UIAlertViewDelegate,UITableViewDelegate,UITableViewDataSource,barcodesScannedDelegate {
func barcodesScanned(barcodes: [String]) {
println("codes=\(barcodes)")
}
Anyone have any ideas why the label won't change and the delegate isn't working?
You need to update all UI in the main thread.
Try this:
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.label1Label.text = code
})
Swift 4:
DispatchQueue.main.async {
self.label1Label.text = code
}

Resources