Passing data between two viewControllers fail - ios

I'm trying to pass data from categoriesTableViewController to quotesContentViewController.Here is the code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let DestViewController : quotesContentsViewController = segue.destinationViewController as! quotesContentsViewController
let categoryString = sender?.titleLabel!!.text
let quotesContentURLString = "http://quotes.rest/qod.json?category=" + categoryString!
if let quotesContentURL = NSURL(string: quotesContentURLString) {
self.updateQuotesContentFeed(quotesContentURL, completion: {(feed) -> Void in
//print(feed!.item.imageURL)*
DestViewController.feed = feed!
DestViewController.author.text = feed!.item.author
DestViewController.quotes.text = feed!.item.quotes
DestViewController.imageURLString = feed!.item.imageURL
//print ("updateQuotesContentFeed")*
//print(DestViewController.imageURLString)*
})
}
}
DestViewController.author.text and DestViewController.quotes.text are passed to quotesContentViewController successfully,but DestViewController.imageURLString failed. print(DestViewController.imageURLString) printed out exactly what I want.(That's why I thought it should have been passed successfully)
Now the code of quotesContentViewController:
import UIKit
class quotesContentsViewController: UIViewController {
var feed: quotesContentFeed?
var urlSession: NSURLSession!
weak var dataTask: NSURLSessionDataTask?
var imageURLString: String!
#IBOutlet var quotes: UILabel!
#IBOutlet var author: UILabel!
#IBOutlet var backgroundImage: UIImageView!
override func viewDidLoad() {
//let request = NSURLRequest(URL: self.imageURL!)
//dataTask = self.urlSession.dataTaskWithRequest(request) {(data, response, error) -> Void //in
//NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
//if error == nil && data != nil {
//let image = UIImage(data: data!)
//self.backgroundImage.image = image
//}
//})
//}
print("viewDidLoad")
print(self.imageURLString)
super.viewDidLoad()
// Do any additional setup after loading the view.
}
When I run it ,it throw an errorfatal error: unexpectedly found nil while unwrapping an Optional value.You can have a look at the screenshot of the error below.

Related

Swift I can't move data with delegate

I'm trying to make a quiz application using the API, I can import the
data into the quizManager file, but I can't transfer the data to the
viewController, When I try to print in quizManger, I can print, but in viewController does not.
how do I move data to viewController?
QuizManager
import Foundation
protocol quizManagerDelegate {
func didUpdateQuiz(_ Quizmanager: QuizManager ,quiz: QuizModel)
}
struct QuizManager {
var delegate: quizManagerDelegate?
func performRequest(){
let urlString = "https://opentdb.com/api.php?amount=1&type=multiple"
if let url = URL(string: urlString){
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { data, response, error in
if error != nil {
print(error!)
return
}
if let safeData = data{
if let quiz = self.parseJSON(quizdata: safeData){
delegate?.didUpdateQuiz(self, quiz: quiz)
}
}
}
task.resume()
}
}
func handle(data: Data?, response: URLResponse?, error: Error?) -> Void {
}
func parseJSON(quizdata: Data) -> QuizModel? {
let decoder = JSONDecoder()
do{
let decodedData = try decoder.decode(Welcome.self, from: quizdata)
let correct = decodedData.results?[0].correct_answer ?? "error"
let quest = decodedData.results?[0].question ?? "error"
let incorrect = decodedData.results?[0].incorrect_answers ?? ["error"]
let question = QuizModel(correctAnswer: correct, question: quest, falseAnswer: incorrect)
// print(question.correctAnswer)
// print(question.question)
// print(question.falseAnswer)
return question
} catch {
print(error)
return nil
}
}
}
QuizData
import Foundation
// MARK: - Welcome
struct Welcome: Codable {
let results: [Result]?
}
// MARK: - Result
struct Result: Codable {
let category: String?
let question, correct_answer: String?
let incorrect_answers: [String]?
}
QuizModel
import Foundation
struct QuizModel {
let correctAnswer : String
let question : String
let falseAnswer : [String]
}
ViewController
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var ChoiceButton4: UIButton!
#IBOutlet weak var ChoiceButton3: UIButton!
#IBOutlet weak var ChoiceButton2: UIButton!
#IBOutlet weak var ChoiceButton1: UIButton!
#IBOutlet weak var QuestionTextView: UITextView!
var quizMangager = QuizManager()
override func viewDidLoad() {
super.viewDidLoad()
QuestionTextView.layer.cornerRadius = 15
quizMangager.performRequest()
self.quizMangager.delegate = self
}
}
extension ViewController : quizManagerDelegate{
func didUpdateQuiz(_ Quizmanager: QuizManager, quiz: QuizModel) {
DispatchQueue.main.async {
print("***")
print(quiz.correctAnswer)
}
}
}
The problem is in viewDidLoad that lines
quizMangager.performRequest()
self.quizMangager.delegate = self
You call performRequest before to delegate it so when performRequest is called var delegate: quizManagerDelegate? is nil . Just call delegate before call function
override func viewDidLoad() {
super.viewDidLoad()
...
quizMangager.delegate = self
quizMangager.performRequest()
...
}
You have a slight mistake in your code. You just need to confirm the delegate first and then call its function .

How to assign a value to a variable in a class from JSON or pass this value to the next function?

Hi everyone!
At the moment, I am taking a course at the Harvard computer science CS50.
My homework is almost ready, but has some incompleteness.
I cannot assign a value from a function to a variable in the class or pass
this value to the next function.
import UIKit
class PokemonViewController: UIViewController {
var url: String!
var name: String!
#IBOutlet var pokemonImage: UIImageView!
#IBOutlet var nameLabel: UILabel!
#IBOutlet var numberLabel: UILabel!
#IBOutlet var type1Label: UILabel!
#IBOutlet var type2Label: UILabel!
#IBOutlet var catchButton: UIButton!
#IBOutlet var descriptionLabel: UILabel!
// MARK: - additional properties
var currentDescURL: String!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadPokemon()
showPokemonDescription()
}
//MARK: - pokemon loading
func loadPokemon() {
guard let pokemonURL = URL(string: url) else { return }
URLSession.shared.dataTask(with: pokemonURL) { (data, _, error) in
guard let data = data else { return }
do {
let result = try JSONDecoder().decode(PokemonResult.self, from: data)
DispatchQueue.main.async {
self.navigationItem.title = self.capitalize(text: result.name)
self.nameLabel.text = self.capitalize(text: result.name)
self.numberLabel.text = String(format: "#%03d", result.id)
for typeEntry in result.types {
if typeEntry.slot == 1 {
self.type1Label.text = typeEntry.type.name
}
else if typeEntry.slot == 2 {
self.type2Label.text = typeEntry.type.name
}
}
// Create Image and Update ImageView
guard let imageURL = URL(string: result.sprites.front_default) else { return }
if let data = try? Data(contentsOf: imageURL) {
self.pokemonImage.image = UIImage(data: data)
}
self.currentDescURL = result.species.url
print(self.currentDescURL)
}
} catch let error { print(error) }
}.resume()
}
// MARK: - Get the URL of a specific Pokémon
func showPokemonDescription() {
guard let pokemonDescriptionURL = URL(string: currentDescURL) else { return }
URLSession.shared.dataTask(with: pokemonDescriptionURL) { (data, _, error) in
guard let data = data else { return }
do {
let result = try JSONDecoder().decode(PokemonDescription.self, from: data)
DispatchQueue.main.async {
// Check and get first pokemon description in English
for index in 0..<result.flavor_text_entries.count {
if result.flavor_text_entries[index].language.name == "en" {
self.descriptionLabel.text = result.flavor_text_entries[index].flavor_text
}
}
}
} catch let error { print(error) }
}.resume()
}
}
The first function loadPokemon() inside itself gets value from JSON and prints the value to the console -> print(self.currentDescURL). Moreover, if you display this value in viewWillAppear, then "nil" will be displayed in the console. I understand that the loadPokemon() function processes the values in the stream that occur at the very end. Perhaps because of this, the variable currentDescURL cannot get the value from the loadPokemon() function and the showPokemonDescription() function cannot use this value since currentDescURL is nil.
I ask you to explain to me what my mistake is and to help finish the assignment.
Move the call for method showPokemonDescription from viewWillAppear to loadPokemon after the currentDescURL property is set.
class PokemonViewController: UIViewController {
//...
var currentDescURL: String!
//...
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadPokemon()
getPreferences()
// <- remove the call from here
}
//...
func loadPokemon() {
//...
self.currentDescURL = result.species.url
self.showPokemonDescription() // <- move the call here
}
//...
func showPokemonDescription() {
//...
}
}

Data persistence after call to webservice iOS

Sorry for my English.
I have many problems in achieving data persistence after call the webservice .
Everything works correctly but I need to use that data in other methods .
As seen in the image once charge data on the screen then I want to give the user the option to use them well or load new data . But not as saving the data recovery webservice .
I was trying to use NSUserDefault but neither work .
From already thank you very much , any response is helpful .
Regards!
ViewController:
class ViewController: UIViewController {
let defaults = NSUserDefaults.standardUserDefaults()
#IBOutlet weak var myLabel2: 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.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let newVC : SecondViewController = segue.destinationViewController as! SecondViewController
let telefono = myLabel2.text!
newVC.recibirString = telefono
}
#IBAction func mostrarAlgo(sender:AnyObject) {
//something
}
}
SecondViewController:
class SecondViewController: UIViewController {
let defaults = NSUserDefaults.standardUserDefaults()
var tel: String = ""
#IBOutlet weak var myLabel1: UITextField!
#IBOutlet weak var myLabel3: UITextField!
#IBOutlet weak var myLabel4: UITextField!
#IBOutlet weak var myLabel5: UITextField!
#IBOutlet weak var myLabel6: UITextField!
#IBOutlet weak var myLabel7: UITextField!
#IBOutlet weak var myLabel8: UITextField!
var recibirString = String()
override func viewDidLoad() {
super.viewDidLoad()
myLabel1.text = recibirString
performRequestAndUpdateUI2(myLabel1.text!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func performRequestAndUpdateUI2(tel:String) {
WebService.llamarWebService (tel,completionHandler: { datos in
guard datos.count == 5 else {
self.myLabel8.text = ("El número ingresado no está registrado.")
return
}
guard datos[0] as! String == "OK" else {
print("not everything was OK")
return
}
dispatch_async(dispatch_get_main_queue()) {
self.myLabel3.text = datos[0] as? String
self.myLabel4.text = datos[1] as? String
self.myLabel5.text = datos[2] as? String
self.myLabel6.text = datos[3] as? String
self.myLabel7.text = datos[4] as? String
self.myLabel8.text = ("Usted está registrado.")
//need save this data
}
})
}
#IBAction func guardarDatos(sender: AnyObject) {
// do something
}
}
WebService:
class WebService{
var telefono = ""
class func llamarWebService(telefono:String, completionHandler: (datos:NSArray)->()){
let urlPath = "http://xxxxxxxxxxx.com.ar/xxxxxxxxxx/forwarder_number?phone=\(telefono)"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
var arreglo:NSArray!
let task = session.dataTaskWithURL(url!,completionHandler: {data,response,error -> Void in
if (error != nil){
print(error?.localizedDescription)
}
let nsdata: NSData = NSData(data: data!)
arreglo = self.retornarDatos(nsdata)
completionHandler(datos: arreglo)
})
task.resume()
}
class func retornarDatos(nsdata: NSData)-> Array<String>{
let datos = NSString(data:nsdata,encoding: NSUTF8StringEncoding)
let partes = datos?.componentsSeparatedByString(",")
var arreglo : [String] = []
for i in partes!{
arreglo.append(i)
}
return arreglo
}
}

Alamofire returns nil always in request

Usually Alamofire working nice with simple urls like:
"http://somesite.com/folder/file.json"
But when I use:
"http://somesite.com/folder/(jsonName.text).json
it always give me a nil... jsonName is a TextField as well...
That's the whole Controller:
import UIKit
import CoreLocation
import Alamofire
import SwiftyJSON
import CoreData
typealias CompletionHandler = (obj:AnyObject?, error:Bool?) -> Void
class LoginViewController: UIViewController, UITabBarControllerDelegate, UITextFieldDelegate, NSURLConnectionDelegate {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
#IBOutlet weak var wePrepareQuestLabel: UILabel!
#IBOutlet weak var downQuestProgres: UIActivityIndicatorView!
#IBOutlet weak var doNotCloseAppLabel: UILabel!
#IBOutlet weak var loginBgImage: UIImageView!
#IBOutlet weak var EmptyCodeError: UILabel!
#IBOutlet weak var loginTabBarItem: UITabBarItem!
#IBOutlet weak var QuestCodeTextField: UITextField!
#IBOutlet weak var loginTextFieldImage: UIImageView!
#IBOutlet weak var downloaded: UIButton!
#IBOutlet weak var createQuestButton: UIButton!
#IBAction func createQuest(sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("WebViewController") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
let Path: String = ""
#IBAction func QuestFetchButton(button: UIButton) {
if QuestCodeTextField.text.isEmpty {
EmptyCodeError.hidden = false
}
else if IJReachability.isConnectedToNetwork() {
}
else
{
QuestCodeTextField.hidden = true
button.hidden = true
EmptyCodeError.hidden = true
createQuestButton.hidden = true
doNotCloseAppLabel.hidden = false
wePrepareQuestLabel.hidden = false
loginTextFieldImage.hidden = true
downQuestProgres.hidden = false
self.downloaded.hidden = false
// questDownloadSaveJSON()
var objThisVC = LoginViewController()
objThisVC.callAndGetResponse { (obj, error) -> Void in
if (obj != nil) {
self.setUpDataInCoreData(obj)
print("ALL DIE")
self.performSegueWithIdentifier("QuestsListViewController", sender: nil)
}
else {
println("Response nil!!")
}
}
}
}
var file:NSFileHandle?
var pathURL: NSURL
{
let folder = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String
let path = folder.stringByAppendingPathComponent("\(QuestCodeTextField.text).json")
let url = NSURL(fileURLWithPath: path)
return url!
}
var code: String = ""
override func viewDidLoad() {
super.viewDidLoad()
QuestCodeTextField.text = code
self.QuestCodeTextField.delegate = self;
}
func setUpDataInCoreData(obj:AnyObject?){
println("Web Serviece Response \(obj)")
let dirEvent = obj as! NSDictionary
var aryEvent = dirEvent.valueForKey("events") as! NSArray
var indexEvent : Int = 0;
for (dirContent) in aryEvent
{
// Create Event Instance
var newItem: Events = NSEntityDescription.insertNewObjectForEntityForName("Events", inManagedObjectContext: self.appDelegate.cdh.backgroundContext!) as! Events
newItem.title = dirContent.valueForKey("title") as! String
newItem.indexID = String(indexEvent++) as String
println(newItem.title)
println(newItem.indexID)
var indexContent : Int = 0;
var aryContent = dirContent.valueForKey("content") as! NSArray
for (dirContentDetail) in aryContent{
var contentEntity: Content = NSEntityDescription.insertNewObjectForEntityForName("Content", inManagedObjectContext: self.appDelegate.cdh.backgroundContext!) as! Content
contentEntity.content_type = dirContentDetail.valueForKey("content_type") as! String
contentEntity.visible = dirContentDetail.valueForKey("visible") as! Bool
contentEntity.indexID = String(indexContent++) as String
println(contentEntity.content_type)
println(contentEntity.visible)
if contentEntity.content_type == "text"{
contentEntity.data_type = dirContentDetail.valueForKey("data") as! String
}
else if contentEntity.content_type == "image" || contentEntity.content_type == "audio" || contentEntity.content_type == "video" || contentEntity.content_type == "choice" {
contentEntity.data_type = ""
if (dirContentDetail.valueForKey("data") != nil && dirContentDetail.valueForKey("data")?.count>0 )
{
var indexImage : Int = 0;
var aryDTImages = dirContentDetail.valueForKey("data") as! NSArray
if aryDTImages.count > 0 {
for strContentDetail in aryDTImages as! [String]{
var objDtImg : DataTypeImage = NSEntityDescription.insertNewObjectForEntityForName("DataTypeImage", inManagedObjectContext: self.appDelegate.cdh.backgroundContext!) as! DataTypeImage
var strURL : NSString = NSString(string: strContentDetail)
objDtImg.urlString = strURL as String
objDtImg.indexID = String(indexImage++) as String
objDtImg.dtImages = contentEntity
// her have to set image to content
contentEntity.content = newItem
}
}
}
}
// here have to set entity to content
contentEntity.content=newItem
}// this is the end of content for loop
}// end of aryEvent
// here to save statement
self.appDelegate.cdh.saveContext(self.appDelegate.cdh.backgroundContext!)
// self.table.reloadData()
}
func callAndGetResponse(complitionHandler : CompletionHandler){
complitionHandler(obj: nil, error: true)
Alamofire.request(.GET, "http://g57732cr.bget.ru/\(QuestCodeTextField.text).json").responseJSON() {
(_, _, data, error) in
if error == nil {
complitionHandler(obj: data, error: false)
}
else{
complitionHandler(obj: nil, error: true)
self.performSegueWithIdentifier("QuestsListViewController", sender: nil)
}
// Fetch all data from Core Data
//self.fetchAllData()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Hide keyboard by tap on the rest of the view
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
view.endEditing(true)
}
//ReturnButton hides keyboard
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "QuestsListViewController"){
var destination = segue.destinationViewController as! UINavigationController
let VC = destination.topViewController as! QuestListViewController
VC.questCode = self.QuestCodeTextField.text
}
}
}

How to pass parse data from tableview to detail view controller?

New to parse backend and coding all together...
Looking to pass data from my HomeTimelineViewController(VC #1), to my ProductDetailViewController(VC #2) through the UIStoryboard segue.
Here is my code for VC #1 :
import UIKit
import Parse
class HomeTimelineViewController: UIViewController, UITableViewDelegate {
#IBOutlet var homeTimelineTableView: UITableView!
var imagePNG = [PFFile]()
var shortDescription = [String]()
var productTitle = [String]()
var productPrice = [String]()
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className: "Product")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {
(products: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// success fetching objects
for product in products! {
self.imagePNG.append(product["imagePNG"] as! PFFile)
self.shortDescription.append(product["shortDescription"] as! String)
self.productTitle.append(product["title"] as! String)
self.productPrice.append(product["price"] as! String)
}
// reload the timeline table
self.homeTimelineTableView.reloadData()
}else {
println(error)
}
}
}
// table view population beginning
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return imagePNG.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let singleCell: ProductTableViewCell = tableView.dequeueReusableCellWithIdentifier("Product Cell") as! ProductTableViewCell
// short description
singleCell.productCellShortDescriptionLabel.text = shortDescription[indexPath.row]
// price
singleCell.productCellPriceLabel.text = productPrice[indexPath.row]
// title
singleCell.productCellTitleLabel.text = productTitle[indexPath.row]
// image
imagePNG[indexPath.row].getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if imageData != nil {
let image = UIImage(data: imageData!)
singleCell.productCellImageview.image = image
}
}
return singleCell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var productDetailVC: ProductDetailViewController = segue.destinationViewController as! ProductDetailViewController
productDetailVC.productDetailTitleLabel = shortDescription
}
}
Here is my code for VC #2 (DetailView):
import UIKit
import Parse
class ProductDetailViewController: UIViewController {
#IBOutlet var tagProduct: UIButton!
#IBOutlet var productDetailTitle: UITextView!
#IBOutlet var productDetailImage: UIImageView!
#IBOutlet var productDetailShortDescription: UITextView!
#IBOutlet var productDetailLongDescription: UITextView!
var productDetailTitleLabel = [String]()
var productDetailImageView = [PFFile]()
var productDetailShortDescriptionLabel = [String]()
var productDetailLongDescriptionLabel = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// tag product button
tagProduct.layer.borderColor = UIColor.blackColor().CGColor
tagProduct.layer.borderWidth = 0.5
tagProduct.layer.cornerRadius = 5
productDetailTitle.text = productDetailTitleLabel
productDetailShortDescription.text = productDetailShortDescriptionLabel
productDetailLongDescription.text = productDetailLongDescriptionLabel
}
}
I can't continue with my code because it keeps giving me an error:
"Cannot assign a value of type '[(String)]' to a value of type 'String!'.
Any tips? Thank you!
Try this:
In TableViewController:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var productDetailVC: ProductDetailViewController = segue.destinationViewController as! ProductDetailViewController
if let selectedArrayIndex = tableView.indexPathForSelectedRow()?.row {
productDetailVC.productDetailTitleLabel = shortDescription[selectedArrayIndex]
}
}
In DetailsView change this:
var productDetailTitleLabel = [String]()
to
var productDetailTitleLabel = String()

Resources