I am having trouble posting the outputs to a label. I have to covert it to a String? The error it seems to give me is "Cannot subscript a value of type JiNode? with an index of type 'Int'" Please help!
var meter = ""
#IBAction func calculate(sender: AnyObject) {
print("start scraping...")
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let url = NSURL(string: "http://uberestimate.com/costs.php")
let jiDoc = Ji(htmlURL: url!)
if jiDoc != nil {
print("html retrived.\n")
self.scrapeHTML(jiDoc!)
}
}
}
#IBOutlet weak var resultLabel: UILabel!
#IBOutlet weak var endingPoint: UITextField!
#IBOutlet weak var startingpoint: 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.
}
private func scrapeHTML(jiDoc: Ji) {
println("parsing...\n")
let bodyNode = jiDoc.xPath("//body")!.first!
var contentDivNode = bodyNode.xPath("//span[#style='font-size:1.3em']").first
if contentDivNode == nil {
print("unexpected format!")
}else{
var cdnArray = contentDivNode[1]
var cdn = cdnArray[0]! as String
self.resultLabel.text = cdn
// println(contentDivNode)
}
return
}
}
You can do something like:
#IBAction func calculate(sender: AnyObject) {
print("start scraping...")
let url = NSURL(string: "http://uberestimate.com/costs.php")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { data, response, error in
if data == nil || error != nil { // in Swift 2, I'd use `guard`, but I tried to keep this backward compatible
print(error)
return
}
dispatch_async(dispatch_get_main_queue()) {
self.scrapeHTML(data!)
}
}
task.resume()
}
private func scrapeHTML(data: NSData) {
print("parsing...\n")
let jiDoc = Ji(data: data, isXML: false)
if let contentDivNode = jiDoc?.xPath("//span[#style='font-size:1.3em']")?.first {
self.resultLabel.text = contentDivNode.content
}
}
I'm using the Swift 2.1 (and I infer from the presence of println that you must be using an earlier version), but I think this is largely the same regardless of Swift version.
BTW, notice that I am dispatching the update of the label back to the main queue (as you called scrapeHTML from a global queue, but UI updates must happen on the main thread). I'm also using NSURLSession rather than dispatching a synchronous network request to a global queue.
Related
This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 1 year ago.
I'm trying to get the readme data for a selected repository from the GitHub api. So, the "content" is the content of the readme file, but is a base64 type. I tried to convert it but when I'm running the app, I get a fatal error "Fatal error: Unexpectedly found nil while unwrapping an Optional value "
Code:
class DetailsViewController: UIViewController {
var details: Item?
var read: Readm?
#IBOutlet weak var forksLabel: UILabel!
#IBOutlet weak var starLabel: UILabel!
#IBOutlet weak var readMeLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
forksLabel.text = "\(details!.forks_count)"
starLabel.text = "\(details!.stargazers_count)"
downloadJSON {
return
}
readMeLabel.text = decodeBase64(word: read!.content) // <- here is the error
}
func downloadJSON (completed: #escaping () -> ()) {
let url = URL (string: "https://api.github.com/repos/\(details!.full_name)/readme")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error == nil {
do {
print("ceva")
self.read = try JSONDecoder().decode(Readm.self, from: data!)
DispatchQueue.main.async {
completed()
}
}catch {
print (error)
}
}
}.resume()
}
func decodeBase64(word: String) -> String {
let base64Decoded = Data(base64Encoded: word)!
let decodedString = String(data: base64Decoded, encoding: .utf8)!
return decodedString
}
}
This is where the error is :
readMeLabel.text = decodeBase64(word: read!.content)
EDITED:
super.viewDidLoad()
forksLabel.text = "\(details!.forks_count)"
starLabel.text = "\(details!.stargazers_count)"
downloadJSON {
if let content = self.read?.content {
self.readMeLabel.text = self.base64Decoded(word: content)
print(self.base64Decoded(word: content))
}
}
}
func base64Decoded(word: String) -> String? {
guard let base64Data = Data(base64Encoded: word) else { return nil}
let decodedData = String(data: base64Data, encoding: .utf8)
return decodedData
}
I have managed how to unwrap things, but now, my label is empty, I made a print statement and is nil. Anyone know why ?
As you have already an asynchronous completion handler use it!.
A single return statement is pretty pointless, move the line to assign the text into the closure.
And unwrap the value always safely, because an error could occur
downloadJSON {
if let content = self.read?.content {
self.readMeLabel.text = self.decodeBase64(word: content)
}
}
I am able to parse JSON and adding cells in Collectionview.. but if i move from this Viewcontroller and coming to viewcontroller then collectionview is not showing.. but added data in JSON
code for adding collectionview and JSON parsing:
class ImageItemModel{
var title: String?
var profileImage: UIImage?
var pic_id: Double?
init(title: String?, imgTitle: UIImage?, pic_id: Double?) {
self.title = title
self.profileImage = imgTitle
self.pic_id = pic_id
}
}
class EditProfileImageViewController: UIViewController {
#IBOutlet weak var titleTextfield: UITextField!
private var imageProfile : UIImage?
private var imagePicker : EasyImagePicker?
#IBOutlet weak var collectionView: UICollectionView!
var arrImageItems = [ImageItemModel]()
#IBAction func imgtitleSaveBtn(_ sender: Any) {
postServiceCall()
}
fileprivate func postServiceCall(){
if titleTextfield.text?.trim() == ""{
return self.view.makeToast("please add service title")
}
let parameters = ["image_title" : titleTextfield.text?.trim() ?? ""]
APIReqeustManager.sharedInstance.uploadMultipartFormData(param: parameters, url: CommonUrl.edit_profile_images, image: imageProfile, fileName: "image", vc: self, isHeaderNeeded: true) {(responseData) in
print("edit profile result \(responseData)")
if let result = responseData.dict?["result"] as? NSDictionary{
let success = result["status"] as? [String : Any]
let message = success?["message"] as? String
if message == "Success"{
let image = result["image"] as? [String : Any]
let picId = image?["id"]
self.arrImageItems.append(ImageItemModel(title: self.titleTextfield.text, imgTitle: self.imageProfile, pic_id: picId as! Double))
self.collectionView.reloadData()
}
else{
self.view.makeToast(CommonMessages.somethingWentWrong)
}
}
}
}
extension EditProfileImageViewController : UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrImageItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell
cell.imgView.image = arrImageItems[indexPath.item].profileImage
cell.lblTitle.text = arrImageItems[indexPath.row].title
cell.deleteButton.tag = indexPath.row
cell.deleteButton.addTarget(self, action: #selector(deleteService(sender:)), for: UIControl.Event.touchUpInside)
return cell
}
}
with the above code i am able to add collectionview cells and able to store data in JSON but.. if i move from this viewcontroller and coming back to this viewcontroller then collectionview is not showing, why? whats wrong? please do help me with code.. i got stuck here from long time.
There are couple of issues that you should fix for this to work properly. I will give you reason for each.-
You are loading your data with the postServiceCall() method which has an asynchronous network call. There is no way to know when the controller is done fetching the data to the arrImageItems array. So, you should have used a completion handler.
Now you are updating the collectionView within the asynchronous dataTask which a background thread. BIG mistake. Whenever you have any UI related task, you do it under the main thread. So, you could refactor the APIReqeustManager.sharedInstance.uploadMultipartFormData() part of your code following way-
APIReqeustManager.sharedInstance.uploadMultipartFormData(param: parameters, url: CommonUrl.edit_profile_images, image: imageProfile, fileName: "image", vc: self, isHeaderNeeded: true) {(responseData) in
print("edit profile result \(responseData)")
if let result = responseData.dict?["result"] as? NSDictionary{
let success = result["status"] as? [String : Any]
let message = success?["message"] as? String
if message == "Success"{
let image = result["image"] as? [String : Any]
let picId = image?["id"]
self.arrImageItems.append(ImageItemModel(title: self.titleTextfield.text, imgTitle: self.imageProfile, pic_id: picId as! Double))
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
else{
DispatchQueue.main.async {
self.view.makeToast(CommonMessages.somethingWentWrong)
}
}
}
}
Now unless you want your viewcontroller to show the data in your collectionView only when the action, imgtitleSaveBtn(_:) is triggered, you need to get data everytime, when your view controller appeared on screen. To fix that issue, you should get the data in the viewWillAppear(_:) method like-
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
postServiceCall()
}
Now, the above two edits should fix your issue depending on how you want to load your collectionview but your code is breaking quite some coding standards. Coding standards sounds like a clique but trust me you want to follow those if you ever want to update the capability of your app without breaking it. The following is just some hints-
Whenever you are in an asynchronous call, you should consider calling a completion handler for returning your data.
Should look into your methods, you are dangerously breaking the single responsibility principal.
In more than one place, you force unwrapped. Bad idea. You need your system to have a fail safe rather than just crashing on you.
Update 2:
Updates with a design pattern:
Compartmentalise your code in MVC pattern. Put the ImageItemModel class in its own file. See the image below to understand the design-
Customize the collectionViewCell within the ImageCollectionViewCell. Let's assume your custom cell has only the outlets.
class ImageCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imgView: UIImageView!
#IBOutlet weak var lblTitle: UILabel!
#IBOutlet weak var deleteButton: UIButton!{
didSet{
deleteButton.addTarget(self, action: #selector(deleteService(_:)), for: .touchUpInside)
}
}
// however this could easily be done with IBAction
#objc func deleteService(_ sender: UIButton){
}
}
Update the postServiceCall and return the data to your controller with a completion handler, means when the postServiceCall is done executing, an array of images or an empty array should be returned based on success or failure. Then the controller can decide what to do with the data, in your case update UI. with couple of refactoring, here is the updated controller code.
import UIKit
import EasyImagePicker
class EditProfileImageViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!{ //for troubleshooting
didSet{ //purpose, do it from code
collectionView.delegate = self
collectionView.dataSource = self
}
}
#IBOutlet weak var titleTextfield: UITextField!
private var imageProfile : UIImage?
private var imagePicker : EasyImagePicker? // you never used this var.
var arrImageItems = [ImageItemModel]()
// any time a view controller appears on screen this method gets called.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
reloadMyCollectionView()
}
#IBAction func imgtitleSaveBtn(_ sender: Any) {
reloadMyCollectionView()
}
fileprivate func reloadMyCollectionView(){
postServiceCall{ images in
self.arrImageItems = images
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
}
// look into escaping closures to understand, why you need it here
fileprivate func postServiceCall(completed: #escaping(_ images: [ImageItemModel])->Void){
// don't force unwrap, get optional values safely with guard let
guard let titleText = titleTextfield.text, titleText == "" else{
return
}
let parameters = ["image_title" : titleText]
APIReqeustManager.sharedInstance.uploadMultipartFormData(param: parameters, url: CommonUrl.edit_profile_images, image: imageProfile, fileName: "image", vc: self, isHeaderNeeded: true) {(responseData) in
print("edit profile result \(responseData)")
//capture the data in local scope and return that array with a completion handler
var imageItems = []
if let result = responseData.dict?["result"] as? NSDictionary{
let success = result["status"] as? [String : Any]
let message = success?["message"] as? String
if message == "Success"{
let image = result["image"] as? [String : Any]
let picId = image?["id"]
imageItems.append(ImageItemModel(title: self.titleTextfield.text, imgTitle: self.imageProfile, pic_id: picId as! Double))
}
}
self.completed(imageItems) // if there is nothing in result,
//imageItems will be empty, otherwise it will have imageItemModel data
}
}
}
extension EditProfileImageViewController : UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrImageItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as? ImageCollectionViewCell{
cell.imgView.image = arrImageItems[indexPath.item].profileImage
cell.lblTitle.text = arrImageItems[indexPath.row].title
cell.deleteButton.tag = indexPath.row
//cell.deleteButton.addTarget(self, action: #selector(deleteService(sender:)), for: UIControl.Event.touchUpInside)
return cell
}
else{
return UICollectionViewCell()
}
}
}
Notice postServiceCall and cellForItemAt methods.
If you still have the same issue then you need to show your whole code to get any further help.
I am using a tabbarcontroller to show 3 xib's. I would like to decode JSON data in the UITabBarController subclass, and then share the data with the view controllers (as I understand that is the preferred way to do this). I had already successfully accomplished this individually in each view controller, where the same JSON data was getting decoded separately 3 times, but I am now trying to make the process more efficient by only dealing with JSON once.
I am currently getting the following error
"Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee7ab7d98)".
Below is the code I am currently using. I'm mostly only including the code for the first view controller, but it is the same for the others
Here is one of the view controllers. Any help would be appreciated, thank you!
class FirstCollectionViewController: UIViewController {
var tbvc = CustomTabBar()
var statisticsData = [Model]()
let firstCellIdentifier = "FirstCellIdentifier"
#IBOutlet weak var FirstCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
FirstCollectionView.delegate = self
FirstCollectionView.dataSource = self
FirstCollectionView.register(UINib(nibName: "FirstCollectionViewCell", bundle: nil),forCellWithReuseIdentifier: firstCellIdentifier)
}
}
Here is the subclasses UITabBarController
import UIKit
class CustomTabBar: UITabBarController {
let website = "https:......."
var statisticsData = [Model]()
override func viewDidLoad() {
super.viewDidLoad()
let firstTab = FirstCollectionViewController(nibName: "FirstCollectionViewController", bundle: nil)
let secondTab = SecondCollectionViewController(nibName: "SecondCollectionViewController", bundle: nil)
let thirdTab = ThirdCollectionViewController(nibName: "ThirdCollectionViewController", bundle: nil)
viewControllers = [firstTab, secondTab, thirdTab]
downloadJSON(website: website) {
firstTab.statisticsData = self.statisticsData
secondTab.statisticsData = self.statisticsData
thirdTab.statisticsData = self.statisticsData
firstTab.FirstCollectionView.reloadData()
secondTab.SecondCollectionView.reloadData()
thirdTab.ThirdCollectionView.reloadData()
}
}
func downloadJSON(website:String, completed:#escaping ()->()){
guard let qurl = URL(string: website) else { return }
URLSession.shared.dataTask(with: qurl) { (data, response, error) in
if error == nil {
do{
self.statisticsData = try JSONDecoder().decode([Model].self, from: data!)
DispatchQueue.main.async{
completed()
}
} catch {
print("JSON Error")
}}
}.resume()
}
}
Once the data is loaded, you should assign the data to the viewControllers that are added in the tabBarController's Child list as below,
downloadJSON(website: website) {
firstTab.statisticsData = self.statisticsData
secondTab.statisticsData = self.statisticsData
thirdTab.statisticsData = self.statisticsData
firstTab.FirstCollectionView.reloadData()
secondTab.SecondCollectionView.reloadData()
thirdTab.ThirdCollectionView.reloadData()
}
You can also remove the below lines from viewDidLoad of FirstCollectionViewController, SecondCollectionViewController and ThirdCollectionViewController
tbvc = tabBarController as! CustomTabBar
statisticsData = tbvc.statisticsData
I'm trying to run an app that allows you to use a search bar and it'll return just temp, city, and conditions. When I run it I get a nil return on the temp and a 'Code: 401 API not valid' error. However, both codes I've tried should be working. I'm probably trying to take the wrong data from OpenWeather but I can't seem to find out where or how to fix it - there are no other errors that appear.
I'm trying to combine two tutorials/guides on this topic, but one uses a different API & the other is in Swift2.
Thanks!
import UIKit
class ViewController: UIViewController, UISearchBarDelegate {
#IBOutlet weak var citySearchBar: UISearchBar!
#IBOutlet weak var cityLabel: UILabel!
#IBOutlet weak var conditionLabel: UILabel!
#IBOutlet weak var tempLabel: UILabel!
var temp: Int!
var condition: String!
var city: String!
let apiID:String = "d7817e07565a0019c5e7851a59eeca73"
var exists: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
citySearchBar.delegate = self
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
let urlRequest = URLRequest(url: URL(string: "http://api.openweathermap.org/data/2.5/weather?q=\(citySearchBar.text!.replacingOccurrences(of: " ", with: "_"))&appid=\(apiID))")!)
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if error == nil {
do {
let weatherData = try JSONSerialization.jsonObject(
with: data!,
options: .mutableContainers) as! [String : AnyObject]
let weather = weatherData
DispatchQueue.main.async {
self.cityLabel.text = self.city
self.tempLabel.text = "\((self.temp))°"
self.conditionLabel.text = weather.description
}
} catch let jsonError {
print(jsonError.localizedDescription)
} } }
task.resume()
} }
First of all the value for temp is a Double not an Int
var temp = 0.0
Second of all you don't set temp in the code. The value for temp is in the dictionary main in weatherData
if let main = weatherData["main"] as? [String:Any],
let tempValue = main["temp"] as? Double {
self.temp = tempValue
print(tempValue)
}
I'm having trouble passing the JSON values (I'm reading successfully) into my textfield on the next viewcontroller because of this unwrapping error, stating my text field is nil.
I'm very stuck. Here's my class that reads the JSON:
class DoOAuth
{
func doOAuthFitbit() -> String{
var name = ""
let oauthswift = OAuth1Swift(
consumerKey: "eabf603efe9e45168d057b60b03f8e94",
consumerSecret: "46b4dfa8c9d59666769e03f887d531a8",
requestTokenUrl: "https://api.fitbit.com/oauth/request_token",
authorizeUrl: "https://www.fitbit.com/oauth/authorize?display=touch",
accessTokenUrl: "https://api.fitbit.com/oauth/access_token")
oauthswift.authorizeWithCallbackURL( NSURL(string: "fitbit://oauth")!,
success:{
credential, response in
let vc: ViewController = ViewController()
let user: OAuthSwiftClient = OAuthSwiftClient(consumerKey: oauthswift.consumer_key, consumerSecret: oauthswift.consumer_secret, accessToken: credential.oauth_token, accessTokenSecret: credential.oauth_token_secret)
let object:[String : AnyObject] = ["oauth_token": credential.oauth_token, "oauth_token_secret" : credential.oauth_token_secret]
user.get("https://api.fitbit.com/1/user/-/profile.json", parameters: object,
success: {
(data: NSData, response: NSHTTPURLResponse) -> Void in
let jsonValues = JSON(data: data, options: NSJSONReadingOptions.AllowFragments, error: nil)
println(jsonValues)
/*public var dictionary: [Swift.String: JSON]?
{
switch self
{
case .Dictionary(let d):
var jsonObject: [Swift.String: JSON] = [:]
for(k,v) in d
{
jsonObject[k] = JSON.wrap(v)
}
return jsonObject
default:
return nil
}
}*/
for(key, subJson) in jsonValues
{
if let nm = subJson["fullName"].string
{
println("\(nm)")
name = nm
}
}
/*for(index: String, subJson: JSON) in jsonValues
{
let name = subJson.dictionary?["fullName"]?.string
println("\(name!)")
//vc.nm.text = name!
main.acceptJson(name!)
}*/
},
failure: {
(error:NSError!) -> Void in
println(error.localizedDescription)
println("error")
})
},
failure: {
(error:NSError!) -> Void in
println(error.localizedDescription)
})
return name
}
}
I call a function that is supposed to receive the JSON strings (acceptJson) located in the next view controller:
class mainMenu: UIViewController
{
var oauthfitbit: DoOAuth = DoOAuth()
var name = ""
//let vc: ViewController = ViewController()
#IBOutlet weak var lbl: UILabel!
#IBOutlet weak var nameField: UITextField!{
didSet{
nameField.text = name
}
}
override func viewWillAppear(animated: Bool)
{
//name = oauthfitbit.doOAuthFitbit()
//self.nameField.text = "Working"
//self.nameField.text = name
}
func acceptJson(info: String!)
{
println("\(info)")
self.nameField.text = info
//name = info
}
}
I get the excepting thrown on the setting nameField.text line stating nameField is nil. How do I get the textfield to store the JSON string?
And here's the initial View Controller:
class ViewController: UIViewController {
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.
}
#IBOutlet weak var nm: UITextField!
//let main: mainMenu = mainMenu()
var name = ""
#IBAction func connectPressed(sender: UIButton)
{
var oauthFitbit: DoOAuth = DoOAuth()
name = oauthFitbit.doOAuthFitbit()
self.performSegueWithIdentifier("loginSuccess", sender: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "loginSuccess")
{
let controller = segue.destinationViewController as! mainMenu
controller.name = name
//vc.nameField.text = "Hello"
}
}
}
How did you create your textfield? Was it through Interface Builder? There have been plenty of times when I've run into these type of problems when using Interface Builder and IBOutlets.
The first step is to make sure your text field is connected to your view controller from the .xib file correctly. Delete the connection and reconnect by control (command?) dragging from IB to your view controller code.
If you're not using IB and still having problems, post the code where you create the textfield. You have to set your view controller as the text field delegate if you're creating it programmatically, I believe. It's been awhile since I've done it that way.
Let us know!
The easiest way to get the new view controller the value of nm is in prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "YourIdentifier" {
let controller = segue.destinationViewController as! mainMenu
controller.name = name
}
}
So, to get this to work, you will need to add a name instance variable (var name = "") to your first view controller, and change main.acceptJson(nm) to name = nm.
Once name is set in your first view controller, you can segue to the second view controller.
In the second view controller, you can change your text field outlet to this:
#IBOutlet weak var nameField: UITextField! {
didSet {
nameField.text = name
}
}
The didSet is a property observer. You can't set the nameField text field directly from the first view controller's prepareForSegue because the text field isn't set up yet when prepareForSegue is called in the first view controller. That's why you're storing it in an instance variable. Then, because of the didSet, your text field's text property will be set as soon as it comes into existence.
UPDATE:
The following is in a class of its own. Let's call that class DoOAuth (looks like that's what you called it):
class DoOAuth {
func doOAuthFitbit() -> String { // Now it's returning a string
var name = "" // Create local variable to return
let oauthswift = OAuth1Swift(
consumerKey: "eabf603efe9e45168d057b60b03f8e94",
consumerSecret: "46b4dfa8c9d59666769e03f887d531a8",
requestTokenUrl: "https://api.fitbit.com/oauth/request_token",
authorizeUrl: "https://www.fitbit.com/oauth/authorize?display=touch",
accessTokenUrl: "https://api.fitbit.com/oauth/access_token")
oauthswift.authorizeWithCallbackURL( NSURL(string: "fitbit://oauth")!,
success:{
credential, response in
//let vc: ViewController = ViewController() // Get rid of this
let user: OAuthSwiftClient = OAuthSwiftClient(consumerKey: oauthswift.consumer_key, consumerSecret: oauthswift.consumer_secret, accessToken: credential.oauth_token, accessTokenSecret: credential.oauth_token_secret)
let object:[String : AnyObject] = ["oauth_token": credential.oauth_token, "oauth_token_secret" : credential.oauth_token_secret]
user.get("https://api.fitbit.com/1/user/-/profile.json", parameters: object,
success: {
(data: NSData, response: NSHTTPURLResponse) -> Void in
let jsonValues = JSON(data: data, options: NSJSONReadingOptions.AllowFragments, error: nil)
println(jsonValues)
/*public var dictionary: [Swift.String: JSON]?
{
switch self
{
case .Dictionary(let d):
var jsonObject: [Swift.String: JSON] = [:]
for(k,v) in d
{
jsonObject[k] = JSON.wrap(v)
}
return jsonObject
default:
return nil
}
}*/
for(key, subJson) in jsonValues
{
if let nm = subJson["fullName"].string
{
println("\(nm)")
name = nm // Store 'nm' in local variable declared above
}
}
}
return name
} // end doOAuthFitbit()
} // end class
Now change your connectPressed() method in ViewController to this:
#IBAction func connectPressed(sender: UIButton)
{
var oauthFitbit: DoOAuth = DoOAuth()
name = oauthFitbit.doOAuthFitbit() // doOAuthFitbit() now returns a String
self.performSegueWithIdentifier("loginSuccess", sender: nil)
}
Now it should work.