After a bit of struggling I finally got my Json file to parse. Although I guess it is parsing.. I am getting nil when Trying to access a value with alot of "objects". This is my code using the swiftyJson library. And here is how my json looks like. The code I am using is
import UIKit
class MapViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let jsonData = getJSON("hls", extn: "json") {
println(jsonData)
let jsonDataResult = JSON(jsonData)
var js = jsonDataResult["name"].string
println("\(js)")
}
}
func getJSON(fileName: String, extn: String) -> NSData?
{
if let fileURL = NSBundle.mainBundle().URLForResource(fileName, withExtension: extn) {
if let data = NSData(contentsOfURL: fileURL) {
return data
}
}
return nil
}
}
I don't understand what I am doing wrong getting the following output in my console. Any help and tips would be appreciated!
When using SwiftyJSON, I believe you need to use the other initializer. That is to say:
let jsonDataResult = JSON(jsonData)
in order for that to work jsonData would already have been run through and parsed once before. The init you are wanting is the following, because you are passing it raw nsData as seen in your output.
let jsonDataResult = JSON(data: jsonData)
Related
Ok I have read so much about NSArray NSDictionary I'm lost now, what I want is to print the value 'name' from the first array item of my custom plist.
This is my plist:
and this is my code in my ViewController.swift:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let path = Bundle.main.path(forResource: "test", ofType: "plist")
let dic = NSArray(contentsOfFile: path!)
print(dic?.firstObject)
}
}
in my console I see:
Optional({
active = 0;
name = "John Doe";
})
I would think that print(dic?.firstObject["name"]) would do the trick
but I get an error: Value of type 'Any?' has no subscripts
So how do I print the values of name and active of my first array?
I know there are lots of answers on SO regarding this question, that's the reason I got so far.
but I just don't know how to fix this.
Kind regards,
Ralph
First of all please never use the NSArray/NSDictionary related API in Swift to read a property list. You are throwing away the type information.
However you can read the values with
let array = NSArray(contentsOfFile: path!) as! [[String:Any]]
for item in array {
let name = item["name"] as! String
let active = item["active"] as! Bool
print(name, active)
}
The dedicated and recommended API is PropertyListSerialization :
let url = Bundle.main.url(forResource: "test", withExtension: "plist")!
let data = try! Data(contentsOf: url)
let array = try! PropertyListSerialization.propertyList(from: data, format: nil) as! [[String:Any]]
A better way is the Codable protocol and PropertyListDecoder
struct User : Decodable {
let name : String
let active : Bool
}
override func viewDidLoad() {
super.viewDidLoad()
let url = Bundle.main.url(forResource: "test", withExtension: "plist")!
let data = try! Data(contentsOf: url)
let array = try! PropertyListDecoder().decode([User].self, from: data)
for item in array {
print(item.name, item.active)
}
}
The code must not crash. If it does you made a design mistake
To use subscripts you first need to cast the object returned by
dic?firstObject
to a dictionary, you can also unwrap the optional at this point.
if let item = dic?firstObject as? [String: Any] {
print(item["name")
}
I need to run a tensorflow lite model in iOS, from input it receives an array (1, 4500, 1), but I don't understand how to send it to input without transforming it as data.
If I print it out to the Interpreter and the Input tells me exactly what I need, but when I run the code it prints out nil output.
I found this in the internet guides:
let resultArray = (
boundingBox: [Float](unsafeData: outputBoundingBox.data) ??
)
But the Float unsafedata function tells me it doesn't exist.
Here's my code:
import UIKit
import TensorFlowLite
import SwiftyJSON
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var opt1 = Interpreter.Options()
opt1.threadCount = 2
let model_path = Bundle.main.path(forResource: "model1", ofType: "tflite")
let int1 = try? Interpreter(modelPath: model_path!, options: opt1)
try? int1?.allocateTensors()
let input = try? int1?.input(at: 0).shape
if let filepath = Bundle.main.path(forResource: "numpytest", ofType: "txt") {
do {
let contents = try String(contentsOfFile: filepath)
let data2 = Data(filepath.utf8)
try? int1!.copy(data2, toInputAt: 0)
try? int1?.invoke()
let salida = try? int1?.output(at: 0)
} catch {
// contents could not be loaded
}
} else {
// example.txt not found!
}
}
}
What am I doing wrong, what do I need to add?
Does anyone have any advice or suggestions?
Greetings!
I got an error while reading json content from remote url and printing on main interface in iOS Simulator.
MBP13"2016 && Mojave 10.14.6 && xcode 10.3(10G8) && swift 5
Here is the code sample. I had change a bit from "https://www.simplifiedios.net/swift-json-tutorial/"
import UIKit
class ViewController: UIViewController {
//the json file url
let URL_POSTS = "https://demo.ghost.io/ghost/api/v2/content/posts/?key=22444f78447824223cefc48062";
//A string array to save all the names
var nameArray = [String]()
//the label we create
#IBOutlet weak var labelTest: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//calling the function that will fetch the json
getJsonFromUrl();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//this function is fetching the json from URL
func getJsonFromUrl(){
//creating a NSURL
let url = NSURL(string: URL_POSTS)
//fetching the data from the url
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
//printing the json in console
print(jsonObj.value(forKey: "posts")!)
//getting the companies tag array from json and converting it to NSArray
if let heroeArray = jsonObj.value(forKey: "posts") as? NSArray {
//looping through all the elements
for heroe in heroeArray{
//converting the element to a dictionary
if let heroeDict = heroe as? NSDictionary {
//getting the name from the dictionary
if let name = heroeDict.value(forKey: "name") {
//adding the name to the array
self.nameArray.append((name as? String)!)
}
}
}
}
OperationQueue.main.addOperation({
//calling another function after fetching the json
//it will show the names to label
self.showNames()
})
}
}).resume()
}
func showNames(){
//looing through all the elements of the array
for name in nameArray{
//appending the names to label
labelTest.text = labelTest.text! + name + "\n";
}
}
}
From the result above, it seems ok that I had found content result in console while fetching json from remote url , but nothing shows up on main interface with iOS simulator.
json result in console
main interface nothing show up in IOS Simulator
I've had some kind of this problem with JSON keys and NSDictionary usage. What worked out for me was just using Decodable protocol. I would recommend using this new API for parsing instead of JSONSerialization.
Here's a few good reads:
https://medium.com/swiftly-swift/swift-4-decodable-beyond-the-basics-990cc48b7375
https://medium.com/xcblog/painless-json-parsing-with-swift-codable-2c0beaeb21c1
I am trying to download a video from my firebase storage. The way I am doing that is by using the .downloadURLWithCompletion function. When ever the function executes, I receive this error
Error Domain=FIRStorageErrorDomain Code=-13010 "Object videos/video1.m4v
does not exist." UserInfo={object=videos/video1.m4v
, bucket=**********.appspot.com, ResponseBody={
"error": {
"code": 404,
"message": "Not Found"
}
}, data=<7b0a2020 22657272 6f72223a 207b0a20 20202022 636f6465 223a2034 30342c0a 20202020 226d6573 73616765 223a2022 4e6f7420 466f756e 64220a20 207d0a7d>, NSLocalizedDescription=Object videos/video1.m4v
does not exist., ResponseErrorDomain=com.google.HTTPStatus, ResponseErrorCode=404}
I have changed my storage settings on firebase to allow unauthenticated access:
I have also checked to make sure that the storage link is correct:
Here is the code that is accessing the Firebase storage:
import UIKit
import AVKit
import AVFoundation
import FirebaseStorage
class VideoViewController: UIViewController
{
var videoUrl:NSURL!
var storageRef:FIRStorageReference!
override func viewDidLoad()
{
let storage = FIRStorage.storage()
storageRef = storage.referenceForURL("gs://**********.appspot.com")
let videosRef = storageRef.child("videos")
let videoName = NSUserDefaults.standardUserDefaults().objectForKey("videoName") as! String
videosRef.child(videoName).downloadURLWithCompletion { (URL, error) -> Void in
if (error != nil)
{
print(error!)
}
else
{
self.videoUrl = URL
do
{
try self.playVideo()
}
catch
{
print("Error")
}
}
}
super.viewDidLoad()
// Do any additional setup after loading the view.
}
So, I tried using a direct link and it worked!
override func viewDidLoad()
{
let storage = FIRStorage.storage()
storageRef = "gs://*************.appspot.com"
let videosRef = "videos"
let videoName = NSUserDefaults.standardUserDefaults().objectForKey("videoName") as! String
storage.referenceForURL("\(storageRef)/\(videosRef)/\(videoName)").downloadURLWithCompletion { (URL, error) in
if (error != nil)
{
print(error!)
}
else
{
self.videoUrl = URL
do
{
try self.playVideo()
}
catch
{
print("Error")
}
}
}
Of course, using a direct link for something like this isn't exactly the best way to get data. So next I compared the two links generated by printing them out. Here is how I printed the first link:
var videoUrl:NSURL!
var storageRef:FIRStorageReference!
override func viewDidLoad()
{
let storage = FIRStorage.storage()
storageRef = storage.referenceForURL("gs://*********.appspot.com")
let videosRef = storageRef.child("videos")
let videoName = NSUserDefaults.standardUserDefaults().objectForKey("videoName") as! String
print(videosRef.child(videoName))
and it printed
gs://***********.appspot.com/videos/video1.m4v
And the second link:
var videoUrl:NSURL!
var storageRef:String!
override func viewDidLoad()
{
let storage = FIRStorage.storage()
storageRef = "gs://***********.appspot.com"
let videosRef = "videos"
let videoName = NSUserDefaults.standardUserDefaults().objectForKey("videoName") as! String
print("\(storageRef)/\(videosRef)/\(videoName)")
What it printed
gs://***********.appspot.com/videos/video1.m4v
Now, I also tried printing the value of videoName to make sure that it was correct and every time that I printed it out it was video1.m4v
I banked out the link to my firebase storage, but I can assure you that the link is correct all around.
Can someone explain to me why I am getting this error? To me everything looks to be in place.
Thanks!
Try this -- if there is an issue with the underlying representation of a ref this may help:
instead of:
videosRef.child(videoName).downloadURLWithCompletion { (URL, error) -> Void in
do:
storage.referenceForURL(String(videosRef.child(videoName))).downloadURLWithCompletion { (URL, error) -> Void in
that is, does referenceForURL of the stringValue do something different than a direct call. It shouldn't -- if it does, it might have something to do with your videoName. Maybe it ends with a slash? Can you post the value of your videoName?
So, if I understand correctly, you want to download the image without passing the full URL path?
If so, I think downloadURLWithCompletion requires the full URL path.
I can't test this, since I don't have my data set up this way (I just store the full URLs to media files in firebase storage to my firebase database), but try this:
videosRef.child(videoName).dataWithMaxSize(INT64_MAX, completion: { (data, error) in
if let error = error {
print("Error downloading: \(error)")
return
}
cell.imageView?.image = UIImage.init(data: data!)
})
In your firebase storage, you haven't placed your video file inside a folder called videos.
And despite this you try to access to .../videos/filename which doesn't exist. Either try to remove the /videos from: gs://***********.appspot.com /videos /video1.m4v
or
Either create a folder called videos inside your firebase storage and then add the same video inside it with the same name (since you cant drag and drop files into other folders), or remove the:
let videosRef = "videos"
from your path.
Hope it helps.
When I run the application Xcode told me that
unexpectedly found nil while unwrapping an Optional value
at the url but the url isn't nil, can someone help?
here is the code
import Foundation
protocol WeatherUndergroundServiceByGeographicalDelegate{
func setWeatherByGeographical(weather:WeatherUnderground)
}
class WeatherUndergoundServiceByGeographical{
var delegate:WeatherUndergroundServiceByGeographicalDelegate?
func getWeatherFromWeatherUnderground(latitude:Double, longitude:Double){
let path = "http://api.wunderground.com/api/48675fd2f5485cff/conditions/geolookup/q/\(latitude,longitude).json"
let url = NSURL(string: path)
//session
let session = NSURLSession.sharedSession()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Error is at here~~~~~~~~~~~~~~~~~~~~~~~~~
let task = session.dataTaskWithURL(url!) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
let json = JSON(data: data!)
//parsing json weather condition from weather api. using swiftyJson
let name = json["current_observation"]["display_location"]["city"].string
let temp = json["current_observation"]["temp_c"].double
let windsp = json["current_observation"]["wind_mph"].double
//prasing the weather data
let weather = WeatherUnderground(cityName: name!, temperature: temp!, windSpeed: windsp!)
if self.delegate != nil{
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.delegate?.setWeatherByGeographical(weather)
})
}
}
task.resume()
}
}
You probably have error in your path string, try this:
let path = "http://api.wunderground.com/api/48675fd2f5485cff/conditions/geolookup/q/\(latitude),\(longitude).json"
The reason is that you are interpolating tuple value \(latitude,longitude) in the string, which adds extra space and makes url string invalid because space is not percent-escaped.
Instead you have to interpolate each value with a comma between them: \(latitude),\(longitude)
let path = "http://api.wunderground.com/api/48675fd2f5485cff/conditions/geolookup/q/\(latitude,longitude).json"
I think you mean:
let path = "http://api.wunderground.com/api/48675fd2f5485cff/conditions/geolookup/q/\(latitude),\(longitude).json"