I am getting a compiler error in the code below. I have imported the required Foundation library so I am not sure exactly what is wrong, please could someone suggest what I might be doing incorrectly or what I might do in order to fix this?
Thanks
import UIKit
import Foundation
class ViewController: UIViewController {
#IBOutlet var areaTxt: UITextField!
#IBOutlet var resultLbl: UILabel!
#IBAction func goBtn(sender: AnyObject) {
if(countElements(areaTxt.text) > 0){
var removedSpaces = areaTxt.text.stringByReplacingOccurrencesOfString(" ", withString: "");
var url = "http://weather-forecast.com/locations/" + removedSpaces + "/forecasts/latest";
self.getWeatherReportForArea(url);
}else{
let alert = UIAlertView()
alert.title = "Alert"
alert.message = "The user location is empty"
alert.addButtonWithTitle("Ok")
alert.show()
}
}
func getWeatherReportForArea(area: String){
var url = NSURL(string: area);
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding);
if(urlContent.bridgeToObjectiveC().containsString("<span class=\"phrase\">")){
var contentArray = urlContent.componentsSeparatedByString("<span class=\"phrase\">");
var newContentArray = contentArray[1].componentsSeparatedByString("</span>");
var value = newContentArray[0].stringByReplacingOccurrencesOfString("°", withString: "º");
dispatch_async(dispatch_get_main_queue()){
self.resultLbl.text = value;
}
}else{
}
}
task.resume();
}
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.
}
}
bridgeToObjectiveC() was removed in Xcode 6 Beta 5. Now bridging is transparent, simply use
if urlContent.containsString("<span class=\"phrase\">") {
...
}
Related
Sorry for my English.
I have many problems in achieving data persistence after call the webservice .
Everything works correctly but I need to use that data in other methods .
As seen in the image once charge data on the screen then I want to give the user the option to use them well or load new data . But not as saving the data recovery webservice .
I was trying to use NSUserDefault but neither work .
From already thank you very much , any response is helpful .
Regards!
ViewController:
class ViewController: UIViewController {
let defaults = NSUserDefaults.standardUserDefaults()
#IBOutlet weak var myLabel2: UITextField!
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.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let newVC : SecondViewController = segue.destinationViewController as! SecondViewController
let telefono = myLabel2.text!
newVC.recibirString = telefono
}
#IBAction func mostrarAlgo(sender:AnyObject) {
//something
}
}
SecondViewController:
class SecondViewController: UIViewController {
let defaults = NSUserDefaults.standardUserDefaults()
var tel: String = ""
#IBOutlet weak var myLabel1: UITextField!
#IBOutlet weak var myLabel3: UITextField!
#IBOutlet weak var myLabel4: UITextField!
#IBOutlet weak var myLabel5: UITextField!
#IBOutlet weak var myLabel6: UITextField!
#IBOutlet weak var myLabel7: UITextField!
#IBOutlet weak var myLabel8: UITextField!
var recibirString = String()
override func viewDidLoad() {
super.viewDidLoad()
myLabel1.text = recibirString
performRequestAndUpdateUI2(myLabel1.text!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func performRequestAndUpdateUI2(tel:String) {
WebService.llamarWebService (tel,completionHandler: { datos in
guard datos.count == 5 else {
self.myLabel8.text = ("El número ingresado no está registrado.")
return
}
guard datos[0] as! String == "OK" else {
print("not everything was OK")
return
}
dispatch_async(dispatch_get_main_queue()) {
self.myLabel3.text = datos[0] as? String
self.myLabel4.text = datos[1] as? String
self.myLabel5.text = datos[2] as? String
self.myLabel6.text = datos[3] as? String
self.myLabel7.text = datos[4] as? String
self.myLabel8.text = ("Usted está registrado.")
//need save this data
}
})
}
#IBAction func guardarDatos(sender: AnyObject) {
// do something
}
}
WebService:
class WebService{
var telefono = ""
class func llamarWebService(telefono:String, completionHandler: (datos:NSArray)->()){
let urlPath = "http://xxxxxxxxxxx.com.ar/xxxxxxxxxx/forwarder_number?phone=\(telefono)"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
var arreglo:NSArray!
let task = session.dataTaskWithURL(url!,completionHandler: {data,response,error -> Void in
if (error != nil){
print(error?.localizedDescription)
}
let nsdata: NSData = NSData(data: data!)
arreglo = self.retornarDatos(nsdata)
completionHandler(datos: arreglo)
})
task.resume()
}
class func retornarDatos(nsdata: NSData)-> Array<String>{
let datos = NSString(data:nsdata,encoding: NSUTF8StringEncoding)
let partes = datos?.componentsSeparatedByString(",")
var arreglo : [String] = []
for i in partes!{
arreglo.append(i)
}
return arreglo
}
}
I have this app that I made with Swift, for fun and because I'm a beginner. Basically what it does is you can enter an artist name and song name and it fetches lyrics from AZLyrics.com based on the artist and song name you entered. For some reason most of the time when I try and load lyrics the first time when I open the app it doesn't load (it loads the 2nd, 3rd, 4th etc time). Here is my code could someone please tell me how I could fix this?
First View controller
import UIKit
var lyricsWithQuotes = ""
var urlError = false
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var songName: UITextField!
#IBOutlet var artistName: UITextField!
#IBAction func search(sender: AnyObject) {
var url = NSURL(string: "http://www.azlyrics.com/lyrics/" + artistName.text.stringByReplacingOccurrencesOfString(" ", withString: "").stringByReplacingOccurrencesOfString("'", withString: "").stringByReplacingOccurrencesOfString(",", withString: "").stringByReplacingOccurrencesOfString(".", withString: "").lowercaseString + "/" + songName.text.stringByReplacingOccurrencesOfString(" ", withString: "").stringByReplacingOccurrencesOfString("'", withString: "").stringByReplacingOccurrencesOfString(",", withString: "").stringByReplacingOccurrencesOfString(".", withString: "").lowercaseString + ".html")
if url != nil {
let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
if error == nil {
var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding) as NSString!
var urlContentArray = urlContent.componentsSeparatedByString("<!-- Usage of azlyrics.com content by any third-party lyrics provider is prohibited by our licensing agreement. Sorry about that. -->")
if urlContent.containsString("It's a place where all searches end!") {
urlError = true
} else {
var lyricsArray = urlContentArray[1].componentsSeparatedByString("<br><br>")
var lyrics = lyricsArray[0] as! String
var lyricsWithoutBR = lyrics.stringByReplacingOccurrencesOfString("<br>", withString: "")
var lyricsWithoutSlashDiv = lyricsWithoutBR.stringByReplacingOccurrencesOfString("</div>", withString: "")
var lyricsWithoutI = lyricsWithoutSlashDiv.stringByReplacingOccurrencesOfString("<i>", withString: "")
var lyricsWithoutSlashI = lyricsWithoutI.stringByReplacingOccurrencesOfString("</i>", withString: "")
lyricsWithQuotes = lyricsWithoutSlashI.stringByReplacingOccurrencesOfString(""", withString: "\"")
}
} else {
urlError = true
}
})
task.resume()
} else {
urlError = true
}
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
override func viewDidLoad() {
super.viewDidLoad()
artistName.delegate = self
songName.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Second View Controller
import UIKit
var lyricsComplete = ""
class ViewController2: UIViewController {
#IBOutlet var lyricsDisplay: UITextView!
override func viewDidAppear(animated: Bool) {
if urlError == true {
urlError = false
lyricsDisplay.text = "Couldn't find that song!"
} else {
lyricsComplete = lyricsWithQuotes
lyricsDisplay.text = lyricsComplete
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
After your NSURLSession has completed - basically this line:
lyricsWithQuotes = lyricsWithoutSlashI.stringByReplacingOccurrencesOfString(""", withString: "\"")
You have two options:
Option One - Programatically launch the view:
let storyboard = UIStoryboard(name: "STORYBOARD NAME HERE", bundle: nil)
let newVC = storyboard.instantiateViewControllerWithIdentifier("VIEW CONTROLLER IDENTIFIER HERE") as! ViewController2
newVC.lyricsComplete = lyricsWithQuotes
If you have a navigation controller:
self.navigationController?.pushViewController(newVC, animated: true)
If you don't have a navigation controller:
self.showViewController(newVC, sender: self)
Options 2 - Trigger the Segue:
performSegueWithIdentifier("SEGUE NAME HERE", sender: nil)
Then intercept the Segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if(segue.identifier == "SEGUE NAME HERE"){
let newVC = segue.destinationViewController as! ViewController2
newVC.lyricsComplete = lyricsWithQuotes
}
}
If you use option 2, make sure the Segue is between the View Controllers and not attached to your button:
Like this:
Not like this:
I want to randomize the image background of weather depending on the weather information. I want to make them work one after the other;
the first function will make a string and the second function use the string produced by the first one.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var cityNameTextField: UITextField!
#IBOutlet weak var weatherFact: UILabel!
#IBOutlet weak var weatherImage: UIImageView!
var weather = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.cityNameTextField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func weatherButton(sender: UIButton) {
weatherInformation()
randomWeatherImage()
}
func showError() {
self.weatherFact.text = "we can't load the weather of \(cityNameTextField.text). please try again"
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.view.endEditing(true)
return true
}
func randomWeatherImage() {
if weatherFact.text != nil {
let string = weather
let regex = NSRegularExpression(pattern: "-?[0-9]{1,3}", options: NSRegularExpressionOptions(), error: nil)
if let matches = regex?.matchesInString(string, options: NSMatchingOptions(), range: NSRange(location: 0, length: count(string))){
let degrees = matches.map { return(string as NSString).substringWithRange($0.range) }
var maxDegree = degrees[0].toInt()
var minDegree = degrees[1].toInt()
var averageWeather:Int = (maxDegree! + minDegree!) / 2
if averageWeather < 0 {
self.weatherImage.image = UIImage(named: "Cold.jpg")
}
else if averageWeather > 20 {
self.weatherImage.image = UIImage(named: "Warm.jpg")
}
else {
self.weatherImage.image = UIImage(named: "Mild.jpg")
}
}
}
}
func weatherInformation() {
let url = NSURL(string: "http://www.weather-forecast.com/locations/" + cityNameTextField.text.stringByReplacingOccurrencesOfString(" ", withString: "-") + "/forecasts/latest")
if url != nil {
let task = NSURLSession.sharedSession().dataTaskWithURL(url!){ (data, response, error) in
var urlError = false
if error == nil {
var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding)
var urlContentArray = urlContent!.componentsSeparatedByString("<span class=\"phrase\">")
if urlContentArray.count > 0 {
var weatherArray = urlContentArray[1].componentsSeparatedByString("</span>")
self.weather = weatherArray[0] as! String
self.weather = self.weather.stringByReplacingOccurrencesOfString("°", withString: "º")
}
else {
urlError = true
}
}
else {
urlError = true
}
dispatch_async(dispatch_get_main_queue()) {
if urlError == true {
self.showError()
}
else {
self.weatherFact.text = self.weather
}
}
}
task.resume()
}
else {
showError()
}
}
}
Just call randomWeatherImage after you set weatherFact.text:
dispatch_async(dispatch_get_main_queue()) {
if urlError == true {
self.showError()
}
else {
self.weatherFact.text = self.weather
self.randomWeatherImage()
}
}
I used path to documents to link external file in app. But when I want to run the project on real iPhone, I replaced the path with NSBundle. Now I'm getting error because of NSBundle(I think) or something else. How can I debug it?
error in console: fatal error: unexpectedly found nil while unwrapping an Optional value
the whole code:
import UIKit
func assign() -> [String]{
let bundle = NSBundle.mainBundle()
let path = bundle.pathForResource("words", ofType: "txt")
let content = String(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: nil)//xcode marked that line with green
let newArray = content!.componentsSeparatedByString("\n")
return newArray
}
class ViewController: UIViewController, UITextFieldDelegate {
let newArray: [String] = assign()
#IBOutlet weak var textBox: UITextView!
#IBOutlet weak var firstInput: UITextField!
#IBOutlet weak var resultLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
firstInput.returnKeyType = .Search
firstInput.delegate = self
textBox.text = ""
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getFromPath() {
//getFromPath() func used to be in assign func.
var letters = firstInput.text
var res = search(set: newArray, letters: letters)
textBox.text! = ""
for element in res {
textBox.text = (textBox.text ?? "") + "\n" + "\(element)"
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
if firstInput.text == "" {
}
else {
getFromPath()
}
self.view.endEditing(true)
return false
}
func search(#set: [String], letters: String) -> [String] {
let result = filter(set) { item in
for char in letters {
if !contains(item, char) {
return false
}
}
return true
}
return result
}
}
It seems like you dont have that file in your bundle.
Make sure the file has been added to the target, check in the inspector.
Wrap critical initialization in
if let someObject = source as? someType
{
}
Drag your file to your project and place it together with your projects files. Make sure you select copy items if needed:
class ViewController: UIViewController {
let wordsUrl = NSBundle.mainBundle().URLForResource("words", withExtension: "txt")!
override func viewDidLoad() {
super.viewDidLoad()
var error: NSError?
if wordsUrl.checkResourceIsReachableAndReturnError(&error) {
println(true)
if let myString = String(contentsOfURL: wordsUrl, encoding: NSUTF8StringEncoding, error: &error) {
let myArray = myString.componentsSeparatedByString("\n")
println(myArray)
} else if let error = error {
println(error.description)
}
} else if let error = error {
println(error.description)
}
// 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.
}
}
I am currently working on an app and I am having an issue. When the user login the webservice, if the login is successful the server responds with JSON, where we use the "firstName" and "SecondName" to then create our "User" which is a struct defined in another file called User.swift . Then, what I want to do is user the "firstName" that has been given to the "User struct" as a UILabel in my homepageview that comes after a successful login. when I try to give my label User.prenom(which is firstName in french) I get the error: User.type does not have a member called...
Here is my code:
the client file where the Login Method is defined:
import Foundation
import Alamofire
import SwiftyJSON
private let _instance = Client()
class Client {
// Router is used to do a request to the server.
private enum Router: URLRequestConvertible {
private static let baseURL = "https://mobile.uqam.ca/portail_etudiant/"
// stores the authentication token.
static var code_perm: String?
static var nip:String?
// Login request.
case Login(String, String)
// URLRequestConvertible protocol.
var URLRequest: NSURLRequest {
// Returns the path, http method and parameters for the request.
var (path: String, method: Alamofire.Method, parameters: [String: AnyObject]) = {
switch self {
case .Login (let code_perm, let nip):
let params: [String: AnyObject] = [
"code_perm": code_perm,
"nip": nip,
]
return ("proxy_dossier_etud.php", .POST, params)
}
}()
// Setup the URLRequest.
let url = NSURL(string: Router.baseURL)
let urlRequest = NSMutableURLRequest(URL: url!.URLByAppendingPathComponent(path))
urlRequest.HTTPMethod = method.rawValue
if let code_perm = Router.code_perm {
if let nip = Router.nip{
parameters["nip"] = nip
parameters["code_perm"] = code_perm
}
}
let encoding = Alamofire.ParameterEncoding.URL
return encoding.encode(urlRequest, parameters: parameters).0
}
}
// Singleton
class var sharedInstance: Client {
return _instance
}
private init() {}
// Login logs in the user with his email and password.
func login(code_perm:String, nip:String, callback:(LoginResponse?) -> Void) {
Alamofire.request(Router.Login(code_perm, nip)).responseJSON { (_, _, data, error) in
if(error != nil) {
callback(nil)
return
}
var json = JSON(data!)
let prenom = json["socio"]["prenom"].stringValue
let nom = json["socio"]["nom"].stringValue
Router.code_perm = code_perm
Router.nip = nip
callback(LoginResponse(
user: User(prenom: prenom,nom: nom)
))
}
}
}
the loginViewController where the login function is called
import UIKit
class LoginViewController: UIViewController {
#IBOutlet weak var LoginScreenImage: UIImageView!
#IBOutlet weak var codeTextField: UITextField!
#IBOutlet weak var nipTextField: UITextField!
#IBOutlet weak var loadingLogin: UIActivityIndicatorView!
let client = Client.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
LoginScreenImage.image = UIImage(named: "UQAMLOGO")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func connect() {
let code_perm = codeTextField.text
let nip = nipTextField.text
self.loadingLogin.startAnimating()
if code_perm != "" && nip != "" {
client.login(code_perm, nip: nip, callback: { (response) in
if let response = response {
self.loadingLogin.stopAnimating()
let homeViewController = self.storyboard!.instantiateViewControllerWithIdentifier("HomeViewController") as HomeViewController
self.showViewController(homeViewController, sender: self)
} else {
self.loadingLogin.stopAnimating()
let badLogin = UIAlertController(title: "Échec de connexion", message: "La combinaison du code permanent et du nip n'est pas bonne", preferredStyle: .Alert)
let reessayer = UIAlertAction(title: "Réessayer", style: .Default, handler: { (reessayer) -> Void in
self.dismissViewControllerAnimated(true , completion: nil)
})
badLogin.addAction(reessayer)
self.presentViewController(badLogin, animated: true, completion: nil)
}
})
}
}
}
the User.swift while where the user struct is
import Foundation
struct User {
var prenom :String
var nom: String
}
struct LoginResponse {
var user: User
}
and finally the HomePageViewController where I try to give the value to my label:
import UIKit
class HomeViewController: UIViewController {
#IBOutlet weak var schedule: UIImageView!
#IBOutlet weak var courses: UIImageView!
#IBOutlet weak var email: UIImageView!
#IBOutlet weak var grades: UIImageView!
#IBOutlet weak var bienvenueLabel: UILabel!
let client = Client.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
schedule.image = UIImage(named:"schedule")
courses.image = UIImage(named: "courses")
email.image = UIImage(named:"mail")
grades.image = UIImage(named:"grades")
bienvenueLabel.text = User.prenom
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Thanks everyone for the help and have a great day/night
Charles
You are accessing the class instead of an instance. Instead, you should pass the response instance to your HomeViewController:
class HomeViewController : .. {
// ...
var loginResponse : LoginResponse
// ...
override func viewDidLoad() {
// ...
bienvenueLabel.text = loginResponse.user.prenom
}
}
// ...
client.login(code_perm, nip: nip, callback: { (response) in
if let loginResponse = response as LoginResponse {
self.loadingLogin.stopAnimating()
let homeViewController = self.storyboard!.instantiateViewControllerWithIdentifier("HomeViewController") as HomeViewController
homeViewController.loginResponse = loginResponse
// assign your instance ^^^^^^^^^^^^^^^^^^^^^^^^
self.showViewController(homeViewController, sender: self)
}
You are accessing the class instead of an instance. Instead, you should pass the response instance to your HomeViewController:
class HomeViewController : .. {
// ...
var loginResponse : LoginResponse
// ...
override func viewDidLoad() {
// ...
bienvenueLabel.text = loginResponse.user.prenom
}
}
// ...
client.login(code_perm, nip: nip, callback: { (response) in
if let loginResponse = response as LoginResponse {
self.loadingLogin.stopAnimating()
let homeViewController = self.storyboard!.instantiateViewControllerWithIdentifier("HomeViewController") as HomeViewController
homeViewController.loginResponse = loginResponse
// assign your instance ^^^^^^^^^^^^^^^^^^^^^^^^
self.showViewController(homeViewController, sender: self)
}
This really isn't very good structure, but it should at least answer your question.