Appending Data To URL In Swift - swift

This may be a rudimentary question, but I am trying to figure out how to "append" strings to a URL, and have them maintain, through View Controllers. More specifically;
I am building a basic File Browser app that is getting its data from a web service (in XML) form. Each time the user taps on a "folder" (which is being displayed as a list of folders in a Table View), another request is made via a NSURL session to get the contents of that folder.
My issue is that the URL string is only appending the name of the row the user tapped on, but I am unsure how to have it populate all rows the user tapped.
let urlString = "http://myurl/"
After the user taps the desired folder...
let urlString = "http://myurl/\(tappedRow)"
// This prints as http://myurl/firstfoldername/
After the user taps the next desired folder...
let urlString = "http://myurl/\(tappedRow)"
// This prints as http://myurl/secondfoldername/
// But I want http://myurl/firstfoldername/secondfoldername/
Since I am just segueing from the TableViewController to itself, and reloading the table, I assume this is working as its supposed to, but I seek to have the url string keep appending the tapped rows to the end, rather than forgetting each time. I was thinking of using NSUserDefaults to keep the last URL, but I realized this must be a common occurrence and perhaps there's a better way. Thanks!

override func viewDidLoad() {
super.viewDidLoad()
let baseUrlString = "http://myUrl/"
var currentUrl = baseUrlString
}
func cellTapped() {
currentUrl += tappedRow
}

You could use a Stack of Strings. I prepared this singleton class.
class StackFolder {
private var path = [String]()
static let sharedInstance = StackFolder()
private init() {}
static private let basePath = "http://myurl"
var baseURL = NSURL(string: basePath + "/")!
func push(folder: String) {
path.append(folder)
}
func pop() {
path.removeLast()
}
func toURL() -> NSURL {
let folders = path.reduce("/") { $0 + $1 + "/" }
let adddress = Stack.basePath + folders
return NSURL(string: adddress)!
}
}
You just need to retrieve the shared instance of Stack and:
invoke push when you want to add a folder to the path
invoke pop when you want to remove the last added folder.
Here it is an example:
StackFolder.sharedInstance.push("folder1")
StackFolder.sharedInstance.toURL().absoluteString // "http://myurl/folder1/"
StackFolder.sharedInstance.push("folder2")
StackFolder.sharedInstance.toURL().absoluteString // "http://myurl/folder1/folder2/"
StackFolder.sharedInstance.pop()
StackFolder.sharedInstance.toURL().absoluteString // "http://myurl/folder1/"
Since Stack is a Singleton you don't need to pass a reference to the same Stack object from one view controller to the other. Each time you write Stack.sharedInstance in your app you automatically get the reference to the only instance of Stack.
Hope this helps.

Declare urlString as instance variable outside any method
var urlString = "http://myurl"
Define a function addPathComponent() and call it every time a row is tapped passing the folder name as the parameter. Using the method stringByAppendingPathComponent avoids confusion with the slash path separators.
func addPathComponent(component : String)
{
urlString = urlString.stringByAppendingPathComponent(component)
// do something with the new urlString value
}

Related

Swift launch view only when data received

I'm getting info from an API using the following function where I pass in a string of a word. Sometimes the word doesn't available in the API if it doesn't available I generate a new word and try that one.
The problem is because this is an asynchronous function when I launch the page where the value from the API appears it is sometimes empty because the function is still running in the background trying to generate a word that exists in the API.
How can I make sure the page launches only when the data been received from the api ?
static func wordDefin (word : String, completion: #escaping (_ def: String )->(String)) {
let wordEncoded = word.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let uri = URL(string:"https://dictapi.lexicala.com/search?source=global&language=he&morph=false&text=" + wordEncoded! )
if let unwrappedURL = uri {
var request = URLRequest(url: unwrappedURL);request.addValue("Basic bmV0YXlhbWluOk5ldGF5YW1pbjg5Kg==", forHTTPHeaderField: "Authorization")
let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
do {
if let data = data {
let decoder = JSONDecoder()
let empty = try decoder.decode(Empty.self, from: data)
if (empty.results?.isEmpty)!{
print("oops looks like the word :" + word)
game.wordsList.removeAll(where: { ($0) == game.word })
game.floffWords.removeAll(where: { ($0) == game.word })
helper.newGame()
} else {
let definition = empty.results?[0].senses?[0].definition
_ = completion(definition ?? "test")
return
}
}
}
catch {
print("connection")
print(error)
}
}
dataTask.resume()
}
}
You can't stop a view controller from "launching" itself (except not to push/present/show it at all). Once you push/present/show it, its lifecycle cannot—and should not—be stopped. Therefore, it's your responsibility to load the appropriate UI for the "loading state", which may be a blank view controller with a loading spinner. You can do this however you want, including loading the full UI with .isHidden = true set for all view objects. The idea is to do as much pre-loading of the UI as possible while the database is working in the background so that when the data is ready, you can display the full UI with as little work as possible.
What I'd suggest is after you've loaded the UI in its "loading" configuration, download the data as the final step in your flow and use a completion handler to finish the task:
override func viewDidLoad() {
super.viewDidLoad()
loadData { (result) in
// load full UI
}
}
Your data method may look something like this:
private func loadData(completion: #escaping (_ result: Result) -> Void) {
...
}
EDIT
Consider creating a data manager that operates along the following lines. Because the data manager is a class (a reference type), when you pass it forward to other view controllers, they all point to the same instance of the manager. Therefore, changes that any of the view controllers make to it are seen by the other view controllers. That means when you push a new view controller and it's time to update a label, access it from the data property. And if it's not ready, wait for the data manager to notify the view controller when it is ready.
class GameDataManager {
// stores game properties
// updates game properties
// does all thing game data
var score = 0
var word: String?
}
class MainViewController: UIViewController {
let data = GameDataManager()
override func viewDidLoad() {
super.viewDidLoad()
// when you push to another view controller, point it to the data manager
let someVC = SomeOtherViewController()
someVC.data = data
}
}
class SomeOtherViewController: UIViewController {
var data: GameDataManager?
override func viewDidLoad() {
super.viewDidLoad()
if let word = data?.word {
print(word)
}
}
}
class AnyViewController: UIViewController {
var data: GameDataManager?
}

Passing Data Indirectly to an Unrelated NSViewController

I am new to macOS Development and I am working on a project for macOS using Xcode 10 and Swift 4.2.
The project contains mainly 3 view controllers.
Firstly, ViewController (the main welcome screen which separates the other two) has two buttons to call the other two respectively.
Secondly, MakeEntry View Controller creates an array of strings data variable using a form type structure comprised of text views and save button etc. which in the end just saves all input data into an array of strings data variable called carrierArray
Thirdly, there is a split view controller for displaying two children view controller namely EntryList and EntryDetail
EntryList (the left pane) contains a Table View to display titles of entries and EntryDetail (the right pane) will contain the description of the title entry (somewhat like the default notes app of macOS)
I want to achieve a simple functionality of being able to access or read that Array of strings variable called carrierArray which is created when the MakeEntry view controller saves it into a global variable defined within its own class file But I want to access that array of strings anywhere and anytime later.
I cannot use delegates and protocols, closures, segues or storyboard identifiers to carry that data because I am not navigating to the Split View Controller straightaway and also because I want to store that data
to manipulate it further before displaying it in the right pane of split view controller (EntryDetail) .
I am unable to figure out whether how it might be possible to achieve this functionality using NSUserDefaults or CoreData.
Therefore I tried using the Notification Centre after storing that array of Strings in a Dictionary namely notifDictionary containing a key called carryData to be stored as the data object of notification centre And with some research and some trials and errors but without any luck all resulting in failure to get that data in the split view controller left pane class file namely (EntryDetail).
Code Snippets are as below, thanks a lot in advance for the kind help.
In MakeEntry View controller:
notifDictionary = ["carryData": carrierArray]
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "dataCarrier") , object: nil, userInfo: notifDictionary)
In EntryList View Controller:
(Tried using both types of selector methods one at a time and even using them together but all without luck! Please Help!)
The Variable datumDict and datumArray and nothing but copy receivers for carrierArray and notifDictionary
var datumDict: [String:[String]] = [:]
var datumArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.getThatDict(_:)), name: NSNotification.Name(rawValue: "dataCarrier") , object: nil)
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "dataCarrier") , object: nil, queue: nil, using: catchNotification)
//datumArray = datumDict["carryData"]!
}
#objc func onNotification(notification:Notification)
{
print(notification.userInfo!)
}
func catchNotification(notification: Notification) -> Void
{
let theDict = notification.object as! NSDictionary
datumDict = theDict as! [String: [String]]
guard let theData = notification.userInfo!["carryData"] as? [String:[String]] else { return }
datumDict = theData
}
#objc func getThatDict(_ notification: NSNotification)
{
print(notification.userInfo ?? "")
if let dict = notification.userInfo as NSDictionary?
{
if let thatDict = dict["carryData"] as? [String: [String]]
{
datumDict = thatDict
}
}
}
With the caveat that "globals and singletons should be avoided," it sounds like they are a good fit for what you're trying to do. As you get more comfortable in Cocoa you can move into more sophisticated means of accomplishing this (dependency injection). Look into this as you get more comfortable with Cocoa.
Create a simple singleton type:
// AppState.swift
class AppState {
// Basic singleton setup:
static let shared = AppState()
private init() {} // private prevents instantiating it elsewhere
// Shared state:
var carrierArray: [String] = []
}
Access it from your view controllers:
// YourViewController.swift:
#IBAction func doSomething(_ sender: Any) {
AppState.shared.carrierArray = ...
}
If you need to update the other view controllers when this shared state changes, notifications are a good tool for that. You could do this with a didSet on carrierArray, or simply trigger the notification manually.

Aynchronous API call not returning data before variable initialization

I am segueing from an initial view to a second view. The first view consists of a text field for a user to enter their search term (account name). That name gets segued to the second view.
I then take this name, and make a call to the Riot API, to return details of their account (name, id, and account ID, level, etc.).
I then update the GUI labels with their credentials (name, id, level).
Now is where this process falls apart; the program does not wait for the API call to complete before it moves forward.
The step breakdown I want is essentially in this order:
1)Use the search term from the segue to call the Riot API
2)Update the GUI with the credentials
3)Initialize some variables with the credentials returned from the Riot API
Instead, this is happening:
1)Use the search term from the segue to call the Riot API
2)Initialize some variables (with credentials from the API (but it cant because they aren't returned yet))
3)Update the GUI with the credentials
The program is skipping forwards and not waiting for data to be returned.
I have come to the understanding that this way of calling the API is 'asynchronous', and that it will not wait for the data to be retrieved before it continues - and the DispatchQueue.main.async{} is useful so long as everything else you need to code follows within the braces.
If you append code after task.resume() it will not use the data retrieved from the call because it isn't returned yet.
My question is essentially: how do I make the 'let task = UrlSession.shared... task.resume() wait for the users credentials so I can then proceed forward with the rest of the code, sequentially - rather than embedding the rest of this view's code within the DispatchQueue.main.async{} braces?
import UIKit
class ViewControllerProfile: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//test to see if we got the name from the segue:
print("from Segue: " + summonerName)
//execute on view load:
let theUser = Summoner(name: summonerName)
print(theUser.name!)
//API - Summoners Details By Summoner Name:
//Construct request for name in secondViewController(PROFILE)
let root:String = "https://euw1.api.riotgames.com"
let entryPoint:String = "/lol/summoner/v3/summoners/by-name/"
let key:String = "?api_key=<key>"
//theUser.name! is a search term (players name)
let completeURL = root + entryPoint + theUser.name! + key
let urlRecieved = URL(string: completeURL.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!)
let task = URLSession.shared.dataTask(with: urlRecieved!){ (data, response, error) in
if error != nil{
print("ERROR")
}
else{
if let content = data{
do{
//Array:
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:Any]
//We now extract the required information from the JSON output with keys:
//Class generics for future parsing:
let summonerID = myJson["id"] as? UInt64
let usersSummonerID:Int = Int(summonerID!)
print(usersSummonerID)
let accountID = myJson["accountId"] as? UInt64
let usersAccountID = Int(accountID!)
print(usersAccountID)
//Required elements for Profile Labels:
let extractName = myJson["name"] as? String
let extractLevel = myJson["summonerLevel"] as? UInt64
//We need to convert the extractLevel variable from UInt64 to String to update a label without an optional:
let usersLevel:String = "\(extractLevel!)"
//We update the gui now using the data we got from the API call:
DispatchQueue.main.async {
//We dispatch the user interface updates to the main thread here:
self.summonerLevelLbl.text = ("Level: " + "\(usersLevel)")
self.summonerNameLbl.text = extractName
//We dispatch the api-returned userObject's attributes to the main thread for assignment here:
self.summonerNameMain = extractName!
self.summonerIDMain = usersSummonerID
self.accountIDMain = usersAccountID
print("dispatch completed\n\n")
//all future code goes here?
}
}
catch{
print("SOMETHING WENT WRONG WITH SERIALIZATION OF NAME X")
}
}
}
}
task.resume()
theUser.name = summonerNameMain
theUser.accountID = accountIDMain
theUser.summonerID = summonerIDMain
print("ASSIGNMENT TEST")
print(theUser.name!)
print(theUser.summonerID!)
print(theUser.accountID!)
}
#IBOutlet weak var summonerNameLbl: UILabel!
#IBOutlet weak var summonerRankLbl: UILabel!
#IBOutlet weak var summonerLevelLbl: UILabel!
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//For Segue:
var summonerName = String()
//For Parsing:
var accountIDMain = Int()
var summonerIDMain = Int()
var summonerNameMain = String()
}
class Summoner:NSObject{
var name:String?
var summonerID:Int?
var accountID:Int?
var matchID:Int?
init(name: String){
self.name = name
}
}
After task.resume()
I want it to wait for the above code to complete before proceeding (let task = URLSession.shared.dataTask... up to task.resume())
Further API calls that require data from previous calls, will be necessary and preferably I would prefer to avoid embedding more code in the async.
Simply move these lines (and the print statements if you want):
theUser.name = summonerNameMain
theUser.accountID = accountIDMain
theUser.summonerID = summonerIDMain
to where you have your comment about "all future code".
Done.

How to Find and Highlight Text in WebView using Swift

I'm working on my first app, and it involves searching for a specific string of text from a large amount of text on a website. I want to be able to search for a specific string and highlight all instances, and as the user types more, it will automatically update the highlighted occurrences. Similar to a find function in any browser.
I found this question on here where they reference using UIWebViewSearch.js to implement this, but I'm not sure how to add that file to my project, or how to use it.
I've added a search bar to my app so far, but haven't done anything with it. Want to use this function along with the search bar to search for the text.
Here is my ViewController code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var webView: UIWebView!
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Place custom HTML onto the screen
let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")
let requestObj = URLRequest(url: myURL!)
webView.loadRequest(requestObj)
// Code that provides a string containing
// JS code, ready to add to a webview.
if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
print(jsString)
} // end if
func searchBarSearchButtonClicked() {
let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(str)')"
self.newsWebView .stringByEvaluatingJavaScript(from: startSearch)
}
} // end of viewDidLoad
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
} // end of didReceiveMemoryWarning
} // end of class ViewController
As #jon-saw says: Welcome to StackOverflow :)
I'll just answer how you can add the JavaScript file to your project...that should get things started right :)
Add a File
You can add a file to Xcode in several ways, but here's one.
In Xcode, in your project, navigate in the left hand Project navigator to where you would like to add your file.
Right click and select "New File..."
Select "Empty" and click "Next"
Name your file UIWebViewSearch.js and click "Create"
You now have an empty file called UIWebViewSearch.js in your project in which you can paste in content.
Use a File
Now you have the file on your project, so now you just need to refer to it. To do so you use Bundle which can load resources in your project for you.
If you look at the answer you referred to, you can see these lines of ObjC code in - (NSInteger)highlightAllOccurencesOfString:(NSString*)str
NSString *path = [[NSBundle mainBundle] pathForResource:#"UIWebViewSearch" ofType:#"js"];
NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
Translated to Swift that would look like this:
if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
print(jsString)
}
And that should give you a String containing all your JS code, ready to add to a WebView for instance.
Hope that gives you something to start with.
Update (after you added a comment to this post)
OK, so you say:
I added my ViewController code to better communicate where I'm at. Kind of confused on how to implement the second part of his code you're referring to. Also not sure how to call the search from the searchBar. Is there a method I need to call within 'searchBarSearchButtonClicked()' method? Just found that method on the apple developer documentation, don't know if it's the correct one, though.
Lets break it down into pieces, I'll start with your ViewController, as there are some problems in your viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Place custom HTML onto the screen
let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")
let requestObj = URLRequest(url: myURL!)
webView.loadRequest(requestObj)
// Code that provides a string containing
// JS code, ready to add to a webview.
if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
print(jsString)
} // end if
func searchBarSearchButtonClicked() {
let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(str)')"
self.newsWebView .stringByEvaluatingJavaScript(from: startSearch)
}
}
You've added your searchBarSearchButtonClicked inside viewDidLoad, but it should be declared as a function by itself (we'll get back to it later).
Furthermore, as I wrote in the comments below:
...One part that is run when the view is loaded and which loads the JavaScript from the bundle.
So lets fix your viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Place custom HTML onto the screen
let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")
let requestObj = URLRequest(url: myURL!)
webView.loadRequest(requestObj)
// Code that provides a string containing
// JS code, ready to add to a webview.
if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
print(jsString)
//Use your jsString on the web view here.
newsWebView.stringByEvaluatingJavaScript(from: jsString)
}
}
As you can see, the searchBarSearchButtonClicked function has been removed and we now use out jsString on the newsWebView.
OK, next part:
Also not sure how to call the search from the searchBar. Is there a method I need to call within 'searchBarSearchButtonClicked()' method? Just found that method on the apple developer documentation, don't know if it's the correct one, though.
You have your searchBarSearchButtonClicked() method which you have found in the Apple Developer documentation, I'm guessing you're meaning this one
As you can see in the documentation (top bar), this function is from the UISearchBarDelete class.
Delegation is a design pattern used in many of Apples frameworks. It allows you to write some generic components and let "someone else" (the delegate) decide what to do with the information from the component (bad explanation I know).
Think of your UISearchBar for instance. If you were to implement a component that other developers could use as a search bar, how would you handle when the user searches for something? I'm thinking, how should your "customers" (the developers using your components) handle this? One way of doing this could be that the developers should subclass UISearchBar and override a "user did search method". You could also use NSNotifications and have the developer register for these notifications. Both of these methods are not pretty or clever.
Enter...the delegate.
UISearchBar has a UISearchBarDelegate and UISearchBarDelegate is just a protocol as you can see. Now the UISearchBar can ask its delegate for certain things, or inform the delegate about important events. So for instance, when the user taps the "Search" button UISearchBar can call delegate.searchBarSearchButtonClicked(self) which means "hey delegate, the user has clicked the search button on me...just thought you should know". And the delegate can then respond as it sees fit.
This means that any class can conform to UISearchBarDelegate and handle the various tasks as it suits in their current situation.
OK, long story, hope you get the gist of it and I think you should read a bit more on delegation as it is a pattern used all over in Apples frameworks :)
So, in your case, you have a UISearchBar, you should give that a delegate like so:
searchBar.delegate = self
And you need to tell the compiler that you intend to implement the UISearchBarDelegate protocol. The Swift convention is to do this in an extension after your ViewController, just to keep things separated:
extension ViewController: UISearchBarDelegate {
}
And then you must also implement the methods of UISearchBarDelegate that you are interested in listening to (note that some protocols have required methods, meaning that you MUST implement them but I don't think UISearchBar has (otherwise you'll find out when the app crashes the first time you run it :)).
So in your case, you mentioned searchBarSearchButtonPressed. As you can see it needs a UISearchBar as a parameter. So your function ends out looking like this:
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let currentSearchText = searchBar.text else {
return
}
let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(currentSearchText)')"
newsWebView.stringByEvaluatingJavaScript(from: startSearch)
}
So... you fetch the current text from your searchBar, add it as a parameter to your startSearch string and hand that startSearch string to your newsWebView.
The entire extensions ends out looking like this.
.... last part of your ViewController class
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
} // end of didReceiveMemoryWarning
} // end of class ViewController
extension ViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let currentSearchText = searchBar.text else {
return
}
let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(currentSearchText)')"
newsWebView.stringByEvaluatingJavaScript(from: startSearch)
}
}
And your viewDidLoad ends out looking like this (you must add yourself as a delegate to the searchBar)
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self //delegate set up
// Do any additional setup after loading the view, typically from a nib.
// Place custom HTML onto the screen
let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")
let requestObj = URLRequest(url: myURL!)
webView.loadRequest(requestObj)
// Code that provides a string containing
// JS code, ready to add to a webview.
if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
print(jsString)
//Use your jsString on the web view here.
newsWebView.stringByEvaluatingJavaScript(from: jsString)
}
}
Wow...that was a lot of writing...hope it helps you.

Show Image from URL in detailView after selection in tableView

I have a tableView which display a list of traffic-cameras parsed from a XML file. When I select a cell, it sends the ImageURL, Roadname, Coordinates etc. via the prepareForSegue method.
In my detailviewcontroller I declare the incoming values as the following:
var selectedFeedURL = String()
var selectedFeedRoadname = String()
var selectedFeedLongitude = String()
var selectedFeedLatitude = String()
I have no problem printing all the values into the log or set it as labels. The problem occurs when I try to load the selectedFeedURL (which is the URL to the image, i.e: http://webkamera.vegvesen.no/kamera?id=559847) and set it to my imageView..
In my viewDidLoad, I have the following code, which should download the image and set it to my imageView named cameraImageView.
if let url = NSURL(string:"\(selectedFeedURL)") {
if let data = NSData(contentsOfURL: url){
print("Suksess")
cameraImageView.image = UIImage(data: data)
}
}
My imageView stays empty and I doesn't get any errors or complains in the debug area. If I print out the selectedFeedURL, the link is there.
The weird part is that if I change
NSURL(string:"\(selectedFeedURL)")
to
NSURL(string:"http://webkamera.vegvesen.no/kamera?id=559847")
Basically changing the variable to a camera URL, it works perfectly.
Soo... any suggestions on what the problem might be?
Much appreciated :)
If there are white spaces and newline characters at the start and end of your URL string, it won't work.
Try:
selectedFeedURL = selectedFeedURL.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet())
if let url = NSURL(string: selectedFeedURL) {
if let data = NSData(contentsOfURL: url){
print("Suksess")
cameraImageView.image = UIImage(data: data)
}
}