I've got Thread 1: Fatal error: Index out of range looping my 7 photos from array in NSViews.
How to fix it?
let url = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Desktop/ArrayOfElements")
do {
let fileURLs = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]).reversed()
let photos = fileURLs.filter { $0.pathExtension == "jpg" }
for index in photos {
let image = [NSImage(data: try Data(contentsOf: index))]
for view in arrayOfViews {
let i = Int(arc4random_uniform(UInt32(photos.count-1)))
view.image = image[i]
}
}
} catch {
print(error)
}
It seems that this line is wrong:
view.image = image[i]
image array has length = 1
Use view.image = image[0] instead
EDIT
let url = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Desktop/ArrayOfElements")
do {
let fileURLs = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]).reversed()
let photos = fileURLs.filter { $0.pathExtension == "jpg" }
for view in arrayOfViews {
let i = Int(arc4random_uniform(UInt32(photos.count-1)))
let image = NSImage(data: try Data(contentsOf: photos[i]))
view.image = image
}
} catch {
print(error)
}
Try to create a category to Collection
extension Collection where Index == Int {
/**
Gives a random element of the collection.
- returns: A random element of the collection.
*/
func randomElement() -> Iterator.Element? {
return isEmpty ? nil : self[Int(arc4random_uniform(UInt32(endIndex)))]
}
}
Usage
let numbers = [1,2,3,4,5,6,7,8,9,10]
let randomNumber = numbers.randomElement()
print(randomNumber!)
Edit:
I guess you are making mistake in the following code
for view in arrayOfViews {
let i = Int(arc4random_uniform(UInt32(photos.count-1)))
view.image = image[i]
}
Let's assume photos objects having 10 elements and image object have less than 10 elements, so in such case, you will get this type of error. So change it to the following
for view in arrayOfViews {
let i = Int(arc4random_uniform(UInt32(image.endIndex)))
view.image = image[i]
}
Related
I'm trying to convert a string into a double in swift. I managed to extract the string from a website (www.x-rates.com) into an array but I cannot convert it after in a double in order to make some work around this number. Can anyone tell me what I'm supposed to do or what I did wrong? I know that my label don't update now but I will do it later, the first thing that I'm trying to do is the conversion.
thx a lot!
Here is the code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var resultLabel: UILabel!
#IBOutlet weak var moneyTextField: UITextField!
#IBAction func convert(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let url = URL(string: "https://www.x-rates.com/calculator/?from=EUR&to=USD&amount=1")!
let request = NSMutableURLRequest(url : url)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
var message = ""
if let error = error {
print(error)
} else {
if let unwrappedData = data {
let dataString = NSString(data: unwrappedData, encoding: String.Encoding.utf8.rawValue)
var stringSeperator = "<span class=\"ccOutputRslt\">"
if let contentArray = dataString?.components(separatedBy: stringSeperator){
if contentArray.count > 0 {
stringSeperator = "<span"
let newContentArray = contentArray[1].components(separatedBy: stringSeperator)
if newContentArray.count > 0 {
message = newContentArray[0]
var message = Float(newContentArray[0])! + 10
}
}
}
}
}
DispatchQueue.main.sync(execute: {
self.resultLabel.text = "the value of the dollar is " + message
}
)}
task.resume()
func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I will talk about convert an Array of String to Array of Double.
In swift Array has a method called map, this is responsable to map the value from array, example, in map function you will receive an object referent to your array, this will convert this object to your new array ex.
let arrOfStrings = ["0.3", "0.4", "0.6"];
let arrOfDoubles = arrOfStrings.map { (value) -> Double in
return Double(value)!
}
The result will be
UPDATE:
#LeoDabus comments an important tip, this example is considering an perfect datasource, but if you have a dynamic source you can put ? on return and it will work, but this will return an array with nil
like that
let arrOfStrings = ["0.3", "0.4", "0.6", "a"];
let arrOfDoubles = arrOfStrings.map { (value) -> Double? in
return Double(value)
}
Look this, the return array has a nil element
If you use the tips from #LeoDabus you will protect this case, but you need understand what do you need in your problem to choose the better option between map or compactMap
example with compactMap
let arrOfStrings = ["0.3", "0.4", "0.6", "a"];
let arrOfDoubles = arrOfStrings.compactMap { (value) -> Double? in
return Double(value)
}
look the result
UPDATE:
After talk with the author (#davidandersson) of issue, this solution with map ou contactMap isn't his problem, I did a modification in his code and work nice.
first I replaced var message = "" per var rateValue:Double = 0.0 and replacedFloattoDouble`
look the final code
let url = URL(string: "https://www.x-rates.com/calculator/?from=EUR&to=USD&amount=1")!
let request = NSMutableURLRequest(url : url)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
var rateValue:Double = 0.0;
if let error = error {
print(error)
} else {
if let unwrappedData = data {
let dataString = NSString(data: unwrappedData, encoding: String.Encoding.utf8.rawValue)
var stringSeperator = "<span class=\"ccOutputRslt\">"
if let contentArray = dataString?.components(separatedBy: stringSeperator){
if contentArray.count > 0 {
stringSeperator = "<span"
let newContentArray = contentArray[1].components(separatedBy: stringSeperator)
if newContentArray.count > 0 {
rateValue = Double(newContentArray[0])! + 10
}
}
}
}
}
//
print("Rate is \(rateValue)"); //Rate is 11.167
}
task.resume()
Hope to help you
The reason your code doesn’t work in my opinion is that you have two variables with the same name that are defined in different scopes and you use the wrong one at the end.
At the beginning you define
var message = ""
And then when converting to a number further down
var message = Float(newContentArray[0])! + 10
So change the last line to something like
var number = Float(newContentArray[0])! + 10
And use number in your calculations. Although I think
var number = Double(message)
should work equally fine since you have assigned newContentArray[0] to message already and Double is more commonly used than Float (I don’t understand + 10)
I am trying to parse the JSON below (actual data is 20x the format listed)
{
message = "";
result = (
{
Ask = "4.8e-05";
BaseVolume = "32.61025363";
Bid = "4.695e-05";
Created = "2017-06-06T01:22:35.727";
High = "5.44e-05";
Last = "4.69e-05";
Low = "4.683e-05";
MarketName = "BTC-1ST";
OpenBuyOrders = 293;
OpenSellOrders = 4186;
PrevDay = "4.76e-05";
TimeStamp = "2018-02-20T00:00:31.863";
Volume = "662575.93818332";
},
This is the code that I have right now. It successfully prints the value "Last" to the console but when I incorporate the Dispatch.Queue, I get a Thread 1: signal SIGBRT not printing the value to the label.
let myJson = try JSONSerialization.jsonObject(with: content) as! [String:Any]
if let info = myJson["result"] as! [[String:Any]]?
{
for i in 0..<20 {
if i == 1
{
if let dict = info[i] as? [String:Any]
{
if let price = dict["Last"]
{
print(price)
//DispatchQueue.main.async
//{
// self.label1.text = price as String
//}
}
}
}
Any help is greatly appreciated!
Most likely your self.label1 outlet isn't connected. Fix that connection.
You should also update the if let that gets the value for the "Last" key as follows:
if let price = dict["Last"] as? String{
print(price)
DispatchQueue.main.async {
self.label1.text = price
}
}
There is some other cleanup you can do as well:
if let myJson = try JSONSerialization.jsonObject(with: content) as? [String:Any] {
if let info = myJson["result"] as? [[String:Any]] {
for (index, dict) in info.enumerated() {
if index == 1 {
if let price = dict["Last"] as? String {
print(price)
DispatchQueue.main.async {
self.label1.text = price
}
} // else no "Last" or not a String
}
}
} // else "result" doesn't contain expected array of dictionary
} // else content isn't a valid JSON dictionary
Avoid all of those forced casts. Especially avoid force casting to an optional.
JSON doesn't use the = sign or the semicolon. Change every = to a colon and every semicolon to a comma, so that
Ask = "4.8e-05";
BaseVolume = "32.61025363";
Bid = "4.695e-05";
Becomes
Ask: "4.8e-05",
BaseVolume: "32.61025363",
Bid: "4.695e-05",
I have the following JSON data structure being pulled from FBSDKGraphRequest.
data = (
{
id = "<USER_ID_GOES_HERE>";
name = "Tom Jones";
picture = {
data = {
"is_silhouette" = 0;
url = "<USER_IMAGE_URL_GOES_HERE>";
};
};
},
{
id = "<USER_ID_GOES_HERE>";
name = "Tom Jones";
picture = {
data = {
"is_silhouette" = 0;
url = "<USER_IMAGE_URL_GOES_HERE>";
};
};
},
{
id = "<USER_ID_GOES_HERE>";
name = "Tom Jones";
picture = {
data = {
"is_silhouette" = 0;
url = "<USER_IMAGE_URL_GOES_HERE>";
};
};
},
I want to extract the data and place it into an array. I am having difficulty with the first "data" key.
Heres my FBSDKGR:
let params = ["fields": "name, picture.type(large)"]
let request = FBSDKGraphRequest(graphPath: "me/taggable_friends", parameters: params)
request!.start { (connection, result, error) -> Void in
if error != nil {
print("There is some error getting friends", error!)
}
else if result != nil {
print("Here is the result", result!)
With an extra dependency, if you don't mind.
import SwiftyJSON
let json = JSON(result) // after you get result from FBSDKGR
let data = json["data"].array
for (index, _) in data.enumerated() {
if let id = json["data", index, "id"].int {
// add to your array
if let name = json["data", index, "name"].string {
// continue nesting...
}
}
}
As your JSOND dta is array of dictionary so , we can cast the result by the following way . First of all we will take two array , one is for names list and other is for picture details . here picture details array is array of dictionary . let's go for code
var namesArray = [String]()
var ImageDetailsArrayDict= [[String :AnyObject]]()
let params = ["fields": "name, picture.type(large)"]
let request = FBSDKGraphRequest(graphPath: "me/taggable_friends", parameters: params)
request!.start { (connection, result, error) -> Void in
if error != nil {
print("There is some error getting friends", error!)
}
else if result != nil {
print("Here is the result", result!)
if let response = result["data"] as? [[String :AnyObject]] {
for i in 0..<response.count {
namesArray.append(response[i]["name"] as! String)
ImageDetailsArrayDict.append(response[i]["picture"])
}
}
}
}
Now , we have two array . so we can easily populate it in the tableView .
Good luck .
i get error index out of range in array
here's my code
.response { request, response, _, error in
self.localPath = destination(NSURL(string: "")!, response!)
self.localPathArray.append(self.localPath!)
}
cell.progressDownload.hidden = false
cell.progressLabel.hidden = false
}
if statusInstantiante == true {
let mainStoryBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc:RedirectMagazineViewController = mainStoryBoard.instantiateViewControllerWithIdentifier("NEXT") as! RedirectMagazineViewController
vc.receiveData = self.localPathArray[indexPath.row] //Error
vc.receiveTitle = titleMagazine[indexPath.item]
self.navigationController?.pushViewController(vc, animated: true)
} else {
print("still downloading")
}
}
I Download pdf file using alamofire download, and get the path (localPath) and append it to localPathArray. the build succeded and can download completely but if i want to view the pdf file it prints index out of range.
Just wrap your line into something like this:
if (self.localPathArray.count > indexPath.row) {
//this condition ensures that your will not request an index that does not exist in the array
vc.receiveData = self.localPathArray[indexPath.row]
}
I am trying to create a file name from the URL. I have to forcefully remove the first item in the array every time. Like the C# implementation where they check for empty string.
Is it possible to remove the "/" in the array? Is there a better way to implement this?
let url = "https://stackoverflow.com/questions/ask"
var filePathComponents:[String] = []
filePathComponents = assetURL.pathComponents as! [String]
filePathComponents.removeAtIndex(0)
let fileName = "-".join(filePathComponents)
I would recommend
filePathComponents.filter { return $0 != "/" }
You don't have to use mutability if you use range indexing (with ..<).
And to make it convenient to use, let's put it in an extension as a computed property.
Example for String:
extension String {
var pathNameWithoutPrefix: String {
get {
return "-".join(self.pathComponents[2 ..< self.pathComponents.count])
}
}
}
let filePath = "http://stackoverflow.com/questions/ask".pathNameWithoutPrefix
println(filePath) // "questions-ask"
Example for NSURL:
extension NSURL {
var pathURLWithoutPrefix: NSURL? {
get {
if let filePathComponents = self.pathComponents as? [String] {
return NSURL(string: "-".join(filePathComponents[1 ..< filePathComponents.count]))
}
return nil
}
}
}
if let url = NSURL(string: "http://stackoverflow.com/questions/ask"),
let fileURL = url.pathURLWithoutPrefix {
println(fileURL) // "questions-ask"
}
Here's the same extensions for Swift 2:
extension String {
var pathNameWithoutPrefix: String {
get {
let str = self as NSString
return "-".join(str.pathComponents[2 ..< str.pathComponents.count])
}
}
}
extension NSURL {
var pathURLWithoutPrefix: NSURL? {
get {
if let filePathComponents = self.pathComponents {
return NSURL(string: "-".join(filePathComponents[1 ..< filePathComponents.count]))
}
return nil
}
}
}
let linkURL = NSURL(string: "http://stackoverflow.com/questions/ask")!
if let comps = linkURL.pathComponents as? [String] {
let fileName = "-".join(dropFirst(comps)) // "questions-ask"
}
Swift 2.0
let linkURL = NSURL(string: "http://stackoverflow.com/questions/ask")!
if let comps = linkURL.pathComponents?.dropFirst() {
let fileName = "-".join(comps) // "questions-ask"
}
Different approach using the host and path properties of NSURL
if let assetURL = NSURL(string: "http://stackoverflow.com/questions/ask") {
let fileNameWithHost = assetURL.host!.stringByAppendingPathComponent(assetURL.path!) // "stackoverflow.com/questions/ask"
let fileNameWithoutHost = assetURL.path!.substringFromIndex(assetURL.path!.startIndex.successor()) // "questions/ask"
}