Why is UITextView's text not being replaced? - ios

I have a short bit of code that is meant to take a string, find words in a library, and replace them from a random array of other words. For some reason, when I hit the button, nothing happens! I made it work in the playground, so what am I doing wrong?
App code:
import UIKit
extension Array {
func randomItem() -> T {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
extension String {
func replace(target: String, withString: String) -> String
{
return self.stringByReplacingOccurrencesOfString(target, withString: withString, options: NSStringCompareOptions.LiteralSearch, range: nil)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
maintext.text = "The Dog Chases the Ball"
self.submit.setTitle("Change It", forState: UIControlState.Normal)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet var maintext: UITextView!
#IBOutlet var submit: UIButton!
#IBAction func submitTapped(sender: UIButton) {
self.submit.setTitle("Again", forState: UIControlState.Normal)
var AllWords = maintext.text
var WordsArray = AllWords.componentsSeparatedByString(" ")
var Dog = ["Pup", "Canine", "Wolf"]
var Ball = ["Frisbee", "Stick", "Car"]
AllWords.replace("Dog", withString: Dog.randomItem()).replace("Ball", withString: Ball.randomItem())
}
}
Play Ground:
import UIKit
import Foundation
extension Array {
func randomItem() -> T {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
extension String
{
func replace(target: String, withString: String) -> String
{
return self.stringByReplacingOccurrencesOfString(target, withString: withString, options: NSStringCompareOptions.LiteralSearch, range: nil)
}
}
var Text = "The Dog Loves to Chase the Ball"
//: Old Text Loaded as an array
var AllWords = Text.componentsSeparatedByString(" ")
//: New Word Library
let Dog = ["Pup", "Canine", "Wolf"]
let Ball = ["Frisbee", "Stick", "Car"]
for element in AllWords {
Text.replace(element, withString: Dog.randomItem())
Text.replace(element, withString: Ball.randomItem())
}
Text.replace("Dog", withString: Dog.randomItem()).replace("Ball", withString: Ball.randomItem())
Thank you!

You're copying maintext.text into AllWords and then replacing the text in AllWords. AllText now has a copy of what's in maintext.text, but is not pointing to the textview's text property. After replacing the text in AllWords, you should assign AllWords to maintext.text:
var AllWords = maintext.text
var WordsArray = AllWords.componentsSeparatedByString(" ")
var Dog = ["Pup", "Canine", "Wolf"]
var Ball = ["Frisbee", "Stick", "Car"]
AllWords.replace("Dog", withString: Dog.randomItem()).replace("Ball", withString: Ball.randomItem())
maintext.text = AllWords // You need set the textview's text here
If that still fails, try jumping back on the main thread when setting the text:
dispatch_async(dispatch_get_main_queue(), { () -> Void in
maintext.text = AllWords
})

The type String in Swift is a value type that means that any change creates a new instance of String.
The string of the text view is left unchanged.
So after the replace task you have to reassign the value to the text view
maintext.text = AllWords
PS: please name variables with a first lowercase letter

Related

How to store my first textfield to not ask for the second time in swift

I created a UITextField where, when the user writes a link and enters, my textfield disappears and my webView appears.
What I am trying to do is, when the user writes the first time their link, the textfield saves that link and when the user opens again the app, the web view opens directly from the last link that the user wrote in the textfield. Basically the stored link should run the second time.
Here is all my code:
import UIKit
import Foundation
let urlKey = "User URL"
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.webView.hidden = true
self.textField.addTarget(self, action: #selector(ViewController.textFieldDidUpdate(_:)), forControlEvents: UIControlEvents.EditingChanged)
if doesURLExist() {
self.textField.text = getURL()
}
}
// Text Field Delegate
func textFieldDidUpdate(textField: UITextField)
{
// Remove Spaces
textField.text = textField.text!.stringByReplacingOccurrencesOfString(" ", withString: "", options: [], range: nil)
// Validate URL
NSURL.validateUrl(textField.text, completion: { (success, urlString, error) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if (success)
{
self.saveURL(urlString!)
self.webView.hidden = false
self.textField.hidden = true
let request = NSURLRequest(URL: NSURL(string: urlString!)!)
self.webView.loadRequest(request)
}
else
{
self.webView.stopLoading()
self.webView.hidden = true
}
})
})
}
#IBAction func dismissKeyboard(sender: AnyObject) {
self.resignFirstResponder()
self.view.endEditing(true)
}
func saveURL(urlString: String) {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(urlString, forKey: urlKey)
}
func getURL() -> String {
let defaults = NSUserDefaults.standardUserDefaults()
let urlString = defaults.objectForKey(urlKey) as! String
return urlString
}
func doesURLExist() -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
guard let _ = defaults.objectForKey(urlKey) where defaults.objectForKey(urlKey) is String else {
return false
}
return true
}
}
Here is my project in GitHub: https://github.com/anappleapp/NSURLvalidation
You'll want to check if the url exists first by calling doesURLExist, if it does, you opt out of presenting that textfield. If it does not exist, call saveURL. NSUserDefaults provides a simple means to store lightweight data.
let urlKey = "User URL"
func saveURL(urlString: String) {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(urlString, forKey: urlKey)
}
func getURL() -> String {
let defaults = NSUserDefaults.standardUserDefaults()
let urlString = defaults.objectForKey(urlKey) as! String
return urlString
}
func doesURLExist() -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
guard let _ = defaults.objectForKey(urlKey) where defaults.objectForKey(urlKey) is String else {
return false
}
return true
}
So your class should look something like:
import UIKit
import Foundation
let urlKey = "User URL"
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.webView.hidden = true
self.textField.addTarget(self, action: #selector(ViewController.textFieldDidUpdate(_:)), forControlEvents: UIControlEvents.EditingChanged)
if(doesURLExist) {
self.textField.text = getURL()
}
// Demo UI Settings
}
}
// Text Field Delegate
func textFieldDidUpdate(textField: UITextField)
{
// Remove Spaces
textField.text = textField.text!.stringByReplacingOccurrencesOfString(" ", withString: "", options: [], range: nil)
// Validate URL
NSURL.validateUrl(textField.text, completion: { (success, urlString, error) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if (success) {
self.saveURL(urlString)
self.webView.hidden = false
self.textField.hidden = true
let request = NSURLRequest(URL: NSURL(string: urlString!)!)
self.webView.loadRequest(request)
} else {
self.webView.stopLoading()
self.webView.hidden = true
}
})
})
}
Don't forget to add the original functions to your class.
You should save the entered string to user defaults. When your app opens you should check user defaults to see if there's already a saved string.
Swift 2 code to save your URL to user defaults:
NSUserDefaults.standardUserDefaults().setObject(urlString!, forKey: "EnteredURLString")
Swift 2 code to check whether there's a saved URL string:
if let urlString = NSUserDefaults.standardUserDefaults().stringForKey("EnteredURLString") {
}

How can I remove last typed digit from a UILabel?

If I type numbers in a label, and if it is a mistake,
how can I remove last typed digit from a UILabel ?
I already put a button for removing the last digit from the label.
The name of the button is back.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var lbltext: UILabel!
#IBOutlet var scrolview1: UIScrollView!
#IBOutlet var fi: UITextField!
#IBOutlet var scrolviewus: UIScrollView!
#IBOutlet var counterLabel: UILabel!
var isFirstTime = true
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func button(sender: AnyObject) {
lbltext.numberOfLines = 0
lbltext.text! = lbltext.text! + "\n" + fi.text! + "\n" + "---"
}
#IBAction func back(sender: AnyObject) {
}
}
Try this:
#IBAction func back(sender: AnyObject) {
if let text = lbltext.text {
lbltext.text = String(text.characters.dropLast())
}
}
Since you want to remove more than just the last digit added, keep the previous state of your label in a property called previous, and just restore it when back is pressed:
var previous = ""
#IBAction func button(sender: AnyObject) {
lbltext.numberOfLines = 0
previous = lbltext.text!
lbltext.text! = lbltext.text! + "\n" + fi.text! + "\n" + "---"
}
#IBAction func back(sender: AnyObject) {
if !previous.isEmpty {
lbltext.text = previous
previous = ""
}
}
For multiple levels of undo, use an array to hold your previous labels:
var previous: [String] = []
#IBAction func button(sender: AnyObject) {
lbltext.numberOfLines = 0
previous.append(lbltext.text!)
lbltext.text = lbltext.text! + "\n" + fi.text! + "\n" + "---"
}
#IBAction func back(sender: AnyObject) {
if let last = previous.last {
lbltext.text = last
previous.removeLast()
}
}
Objective-c
label.text = [label.text stringByReplacingCharactersInRange:NSMakeRange(label.text.length - 1, 1) withString:#""];
Swift
if let text = label.text{
let nsRange : NSRange = NSRange(location: (text.characters.count) - 1, length: 4)
label.text = (label.text! as NSString)
.stringByReplacingCharactersInRange(nsRange, withString: "")
}
let name: String = self.display.text!
let stringLength = count(name)
let substringIndex = stringLength - 1
lbltext.text = (name as NSString).substringToIndex(substringIndex)
Have you had just tried the delegate shouldChangeCharactersInRange? :
Remember to do under viewDidLoad:
fi.delegate = self
Then call the delegate:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if string.characters.count == 0 && range.length > 0 {
// Back pressed
// do whatever you want with your labels..
return false
}
return true
}
#IBAction func back(sender: AnyObject) {
for var i:Int = 0 ; i < 4 ; i++
{
if let text = lbltext.text
{
lbltext.text = String(text.characters.dropLast())
}
}
}

Send array by segue to new view controller swift iOS 9

I am attempting to send an array of data to a new view controller and I'm currently getting the error fatal error: unexpectedly found nil while unwrapping an Optional value
Im using the API data from www.thecocktaildb.com
Example:
http://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita
Not sure what I'm doing wrong. Tried debugging and checking values before the segue in my search view controller and they're accurate.
Heres my code:
Main Storyboard
SearchViewController
class SearchViewController: UIViewController, UISearchBarDelegate, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var TableView: UITableView!
#IBOutlet weak var SearchBar: UISearchBar!
var valueToPass:Drinks!
var isSearching : Bool = false
class Drinks {
var idDrink: Int = 0
var strDrink: String = ""
var strCategory: String = ""
var strAlcoholic: String = ""
var strGlass: String = ""
var strInstructions: String = ""
var strDrinkThumb: String = ""
var strIngredient1: String = ""
var strIngredient2: String = ""
var strIngredient3: String = ""
var strIngredient4: String = ""
var strIngredient5: String = ""
var strIngredient6: String = ""
var strIngredient7: String = ""
var strIngredient8: String = ""
var strIngredient9: String = ""
var strIngredient10: String = ""
var strIngredient11: String = ""
var strIngredient12: String = ""
var strIngredient13: String = ""
var strIngredient14: String = ""
var strIngredient15: String = ""
var strMeasure1: String = ""
var strMeasure2: String = ""
var strMeasure3: String = ""
var strMeasure4: String = ""
var strMeasure5: String = ""
var strMeasure6: String = ""
var strMeasure7: String = ""
var strMeasure8: String = ""
var strMeasure9: String = ""
var strMeasure10: String = ""
var strMeasure11: String = ""
var strMeasure12: String = ""
var strMeasure13: String = ""
var strMeasure14: String = ""
var strMeasure15: String = ""
}
var TableData:Array< Drinks > = Array < Drinks >()
override func viewDidLoad() {
super.viewDidLoad()
for subView in self.SearchBar.subviews
{
for subsubView in subView.subviews
{
if let textField = subsubView as? UITextField
{
textField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: ""))
}
}
}
self.SearchBar.delegate = self
self.TableView.delegate = self
self.TableView.dataSource = self
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if self.SearchBar.text!.isEmpty {
self.isSearching = false
}else{
self.isSearching = true
let userSearchInput = self.SearchBar.text!.lowercaseString
let newString = userSearchInput.stringByReplacingOccurrencesOfString(" ", withString: "%20", options: NSStringCompareOptions.LiteralSearch, range: nil)
let postEndpoint: String = "http://www.thecocktaildb.com/api/json/v1/1/search.php?s=" + newString
guard let url = NSURL(string: postEndpoint) else {
print("Error: cannot create URL")
return
}
let urlRequest = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("error calling GET on www.thecocktaildb.com")
print(error)
return
}
let post: NSDictionary
do {
post = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as! NSDictionary
} catch {
print("error trying to convert data to JSON")
return
}
var count = 1
if let drinks = post["drinks"] as? [NSDictionary] {
self.TableData.removeAll()
for drink in drinks {
let adrink = Drinks()
if let strDrink = drink["strDrink"] as? String {
print(String(count) + ". " + strDrink)
adrink.strDrink = strDrink
count++
}
if let strCategory = drink["strCategory"] as? String {
print(" Category: " + strCategory)
adrink.strCategory = strCategory
}
if let strDrinkThumb = drink["strDrinkThumb"] as? String {
print(" Thumbnail Image: " + strDrinkThumb)
adrink.strDrinkThumb = strDrinkThumb
}
self.TableData.append(adrink)
self.TableView.reloadData()
}
}
})
task.resume()
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
//title = TableData[indexPath.row].strDrink
cell.textLabel?.text = TableData[indexPath.row].strDrink;
let imageString = TableData[indexPath.row].strDrinkThumb
if (imageString == ""){
let noDrinkImage : UIImage = UIImage(named: "noimage.jpg")!
cell.imageView!.image = noDrinkImage
}else{
let drinkImage = UIImage(data: NSData(contentsOfURL: NSURL(string:TableData[indexPath.row].strDrinkThumb)!)!)
cell.imageView!.image = drinkImage
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
print(TableData[indexPath.row].strDrink)
valueToPass = TableData[indexPath.row]
//self.performSegueWithIdentifier("drinkSegue", sender: TableData[indexPath.row])
}
// hide kwyboard when search button clicked
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
self.SearchBar.resignFirstResponder()
}
// hide keyboard when cancel button clicked
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
self.SearchBar.text = ""
self.SearchBar.resignFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DrinkSegue") {
// initialize new view controller and cast it as your view controller
let drinkViewController = segue.destinationViewController as! DrinkViewController
// your new view controller should have property that will store passed value
drinkViewController.passedValue = valueToPass
}
}
}
DrinkViewController.swift
class DrinkViewController: UIViewController {
#IBOutlet weak var DrinkNameLabel: UILabel!
var passedValue : SearchViewController.Drinks!
override func viewDidLoad() {
super.viewDidLoad()
DrinkNameLabel.text = passedValue!.strDrink
// 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.
}
}
Do it like this instead
In your didSelectRowAtIndexPath pass the array
self.performSegueWithIdentifier("drinkSegue", sender: TableData[indexPath.row])
Here you need to pass the array to your DrinkViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DrinkSegue") {
// initialize new view controller and cast it as your view controller
let drinkViewController = segue.destinationViewController as! DrinkViewController
// your new view controller should have property that will store passed value
drinkViewController.passedValue = valueToPass
// declare myArray in your drinkViewController and then assign it here
// now your array that you passed will be available through myArray
drinkViewController.myArray = sender
}
}
Update
After I got your project I noticed that the issue you had was that you did drag a segue from the tableView to the drinksController directly - what happened is that didSelectRowAtIndexPath will not be called and your sender will always be nil drinkViewController.myArray = sender as! Drinks.
I changed that by dragging the segue from the viewController to the drinksController instead.

Most of the time HTML doesn't load first time

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:

Swift: Watchkit Table not populating

This is an app that I already made for iPhone and want to make it available for the apple watch.
I have a function that uses SwiftyJSON to parse a JSON and collect various information that I use to populate my table. In willActiviate I loop through all of my rows and index them to get the information I need to display on the label. Or at least, that's what I'm trying to do. When I run it, the correct amount of labels are shown, but the labels do not display anything. I've also created loadTableData() to manually reload the tableData.
If I'm doing something completely wrong when trying to populate it, or if I'm doing something else wrong, a little point in the right direction would be appreciated.
My code:
#IBOutlet weak var earthTable: WKInterfaceTable!
private func loadTableData() {
getEarthquakeInfo { (info) in
self.earthTable.setNumberOfRows(0, withRowType: "earthquake")
self.earthTable.setNumberOfRows(info.count, withRowType: "earthquake")
}
}
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
self.loadTableData()
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
for index in 0..<self.earthTable.numberOfRows {
var currentRow = self.earthTable.rowControllerAtIndex(index) as earthquakeViewController
let time = info[self.earthTable.indexOfAccessibilityElement(currentRow)].time
let mag = info[self.earthTable.indexOfAccessibilityElement((currentRow))].mag
let title = info[self.earthTable.indexOfAccessibilityElement(currentRow)].title
currentRow.titleLabel.setText("\(title)")
currentRow.timeLabel.setText("\(time)")
currentRow.magLabel.setText("\(mag)")
}
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
}
My entire function where I parse the JSON if needed:
class InterfaceController: WKInterfaceController {
var info = [AppModel]()
func getEarthquakeInfo(completion: (results : [AppModel]) ->Void ){
DataManager.getEarthquakeDataFromFileWithSuccess {
(data) -> Void in
let json = JSON(data: data)
if var JsonArray = json.array {
JsonArray.removeAtIndex(0)
for appDict in JsonArray {
// parsing
var ids: String? = appDict["id"].stringValue
var title: String? = appDict["title"].stringValue
var time: String = appDict["time"].stringValue
var lattitude: String? = appDict["lat"].stringValue
var longitude: String? = appDict["lng"].stringValue
var north: String? = appDict["north"].stringValue
var west: String? = appDict["west"].stringValue
var mag: String? = appDict["mag"].stringValue
var depth: String? = appDict["depth"].stringValue
var timeStamp: String? = appDict["timestamp"].stringValue
// Splitting up title string into 2 parts
let newString = title!.stringByReplacingOccurrencesOfString(" ", withString: " - ", options: NSStringCompareOptions.LiteralSearch, range: nil)
var title2strings = newString.componentsSeparatedByString(" - ")
var scale = title2strings[0]
var location = title2strings[1]
// replacing M in scale string with Richter Scale
let scaleString = scale.stringByReplacingOccurrencesOfString("ML", withString: "Magnitude", options: NSStringCompareOptions.LiteralSearch, range: nil)
let scaleString2 = scaleString.stringByReplacingOccurrencesOfString("mb", withString: "Magnitude", options: NSStringCompareOptions.LiteralSearch, range: nil)
let scaleString3 = scaleString2.stringByReplacingOccurrencesOfString("Mw", withString: "Magnitude", options: NSStringCompareOptions.LiteralSearch, range: nil)
let scaleString4 = scaleString3.stringByReplacingOccurrencesOfString("MD", withString: "Magnitude", options: NSStringCompareOptions.LiteralSearch, range: nil)
let scaleString5 = scaleString4.stringByReplacingOccurrencesOfString("M ", withString: "Magnitude ", options: NSStringCompareOptions.LiteralSearch, range: nil)
//Formatting the date
var date = NSDate(dateString: time).getDatePart()
// Collecting all the information
var information = AppModel(idEarth: ids, title: title, time: date, lat: lattitude, lng: longitude, north: north!, west: west, mag: mag, depth: depth, timeStamp: timeStamp, location: location, scale: scaleString5)
self.info.append(information)
//sorting array by highest magnitude
// self.info.sort({$0.mag > $1.mag})
// returning the completion handler
completion(results: self.info)
}
}
}
}
My AppModel file that I used (if needed):
import Foundation
import WatchKit
class AppModel: NSObject, Printable {
let idEarth: String
let title: String
let time: String
let lat: String
let lng: String
let north: String
let west: String
let mag: String
let depth: String
let timeStamp: String
let scale: String
let location: String
override var description: String {
return "ID: \(idEarth), TITLE: \(title), TIME: \(time), LAT: \(lat), LNG: \(lng), NORTH: \(north), WEST: \(west), MAG: \(mag), DEPTH: \(depth), TIMESTAMP: \(timeStamp), LOCATION: \(location), SCALE: \(scale) \n"
}
init(idEarth: String?, title: String?, time: String?, lat: String?, lng: String?, north: String, west: String?, mag: String?, depth: String?, timeStamp: String?, location: String?, scale: String?) {
self.idEarth = idEarth ?? ""
self.title = title ?? ""
self.time = time ?? ""
self.lat = lat ?? ""
self.lng = lng ?? ""
self.north = north ?? ""
self.west = west ?? ""
self.mag = mag ?? ""
self.depth = depth ?? ""
self.timeStamp = timeStamp ?? ""
self.location = location ?? ""
self.scale = scale ?? ""
}
}
I think that your problem is that you are trying to populate your tableView in willActivate but you are not even sure that you already have the data (your completion handler from getEarthquakeInfo may not be reached).
You should try to set up your cells just after you set the number of rows.
And by the way, why are you setting two times the number or rows?
Try something like this
#IBOutlet weak var earthTable: WKInterfaceTable!
private func loadTableData() {
getEarthquakeInfo { (info) in
self.earthTable.setNumberOfRows(info.count, withRowType: "earthquake")
//Create cells
for index in 0..<self.earthTable.numberOfRows {
var currentRow = self.earthTable.rowControllerAtIndex(index) as earthquakeViewController
let time = info[self.earthTable.indexOfAccessibilityElement(currentRow)].time
let mag = info[self.earthTable.indexOfAccessibilityElement((currentRow))].mag
let title = info[self.earthTable.indexOfAccessibilityElement(currentRow)].title
currentRow.titleLabel.setText("\(title)")
currentRow.timeLabel.setText("\(time)")
currentRow.magLabel.setText("\(mag)")
}
}
}
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
self.loadTableData()
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
}

Resources