Text appear irregularly in UI Table - uitableview

was trying to work on my little App of weather forecast by city name !
but i had a problem about irregularly overlapped while iOS simulator was running .
i had checked inspector panel and constrains that i've set up. But nothing works so far !
and my codes as below :
import UIKit
class ViewController: UIViewController {
#IBOutlet var cityEnter: UITextField!
#IBOutlet var resultLabel: UILabel!
#IBAction func findingWeather(sender: AnyObject) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let url = NSURL(string: "http://www.weather-forecast.com/locations/Paris/forecasts/latest")!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
if let urlContent = data{
let webContent = NSString(data: urlContent, encoding: NSUTF8StringEncoding)
let webSiteArray = webContent?.componentsSeparatedByString("3 Day Weather Forecast Summary:</b><span class=\"read-more-small\"><span class=\"read-more-content\"> <span class=\"phrase\">")
if webSiteArray?.count > 0 {
let weatherArray = webSiteArray![1].componentsSeparatedByString("</span>")
if weatherArray.count > 0 {
let weatherSummary = weatherArray[0]
dispatch_async(dispatch_get_main_queue(),{ () -> Void in
self.resultLabel.text = weatherSummary
})
}
}
}
}
task.resume()
}

As far as know about this issue it is due the Extra 16px margin taken by IPHONE 6 PLUS you have to disable that extra margin.(both leading and trainling)
Navigate to Inspector Area where all your constrain Listed:
First Double Click On Leading Horizontal Constraint then you will get following screen Click on SuperView-Leading:
Uncheck the Relative to Margin
After this their is no way to go back just click anywhere on screen or select any other control then repeat this same for Trailing Constraint.
I hope this will help

Related

Parse JSON Result To UILabel in Swift

I'm really new into swift & currently learning API by doing a project that shows list of games from rawg.io referring to the website's doc. I created GameFeed.swift & GameDetail.swift to pull name, release date, and rating from it and working fine in my console.
GameFeed.swift :
struct GameFeed: Codable {
let results:[GameDetail]
}
GameDetail.swift :
struct GameDetail: Codable {
let name:String
let released:String
let rating:Double
}
Now i'm trying to put the results to a simple UIlabel like gameName.text, gameReleased.text & gameRating.text from ViewController.swift so it will be show in Main.Storyboard
i did research on google about how to show it to these UIlabel by using DispatchQueue.main.async but when i'm declaring it, it receiving error :
Value of type 'GameFeed' has no member 'name'
same error messages also happened to released & rating. This is my ViewController.Swift :
class ViewController: UIViewController {
#IBOutlet weak var gameName: UILabel!
#IBOutlet weak var gameReleased: UILabel!
#IBOutlet weak var gameRating: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Defining API Site
let urlString = "https://api.rawg.io/api/games"
let url = URL(string: urlString)
guard url != nil else {
return
}
// Calling API
let session = URLSession.shared
let dataTask = session.dataTask(with: url!){
(data, response, error) in
if error == nil && data != nil {
let decoder = JSONDecoder()
do {
let gameFeed = try decoder.decode(GameFeed.self, from: data!)
print(gameFeed)
DispatchQueue.main.async {
self.gameName.text = gameFeed.name
self.gameReleased.text = gameFeed.released
self.gameRating.text = gameFeed.rating
}
}
catch {
print("Error Parsing JSON")
}
}
}
dataTask.resume()
}
}
What should i do to make it possible to parse the data to labels?
The GameFeed contains an Array of GameDetails. But you are trying to set a single GameDetail on those labels. You should first pull out a single GameDetail from that array, then assign it in a way you like.
DispatchQueue.main.async {
let gameDetail = gameFeed.results.first // <- This will return the first one
self.gameName.text = gameDetail?.name
self.gameReleased.text = gameDetail?.released
self.gameRating.text = gameDetail?.rating
}

Swift NavigationBar Press "Back" to get values, why?

I am using some values to perform some calculations. For testing purposes I show in Label1 a value as string, since it is stored as a string and in Label2 I show a casted value as a Double since I need them at the end as doubles for my calculations.
The weird thing is, that when I access the ViewController the first time it doesn't show any values. But if I go back and klick on it again using the navigation controller it actually works. But I need the values right away cause my original intention is as I said, not showing some labels but rather making some calculations with it.
I made a little gif to show you what the problem is but I have problem with adding photos. Basically what happens is, that I click on the ViewController with the labels and nothing is showed. I go back and press again and the values will be showed in the labels.
Why is that and how can it be showed right away/ used for calculations right away
Thanks for the help. :)
class AHPfinalPreferencesViewController: UIViewController {
var ahpPrios = [AHPPriorityStruct]()
let decoder = JSONDecoder()
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
let ajkpXc = globaLajkpXc
let ajkpXijr = globaLajkpXijr
let valueA = globaLajkpXc
let valueB = Double(globaLajkpXijr)
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UserService.ahpPref(for: User.current) { (ahpPrios) in
self.ahpPrios = ahpPrios
print("This is our AHP PRIOS", ahpPrios)
for ahpPrio in ahpPrios {
print(ahpPrio)
}
print("this is the global ajk. ", self.ajkpXc)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Mark: - Get Data
label1.text = valueA
label2.text = "\(String(describing: valueB))"
// MARK: - Set Values for calculation
// setValues()
// ahpCalculation()
}
}
Could it be because of the globalVariables? I know that it is not the right way to do it but for my purposes its absolutely "okay"
import Foundation
import FirebaseAuth.FIRUser
import FirebaseDatabase
import FirebaseUI
import FirebaseAuth
import CodableFirebase
var globaLajkpXc: String = String()
var globaLajkpXijr: String = String()
var globaLajkpXqpa: String = String()
struct UserService {
static func ahpPref(for user: User, completion: #escaping ([AHPPriorityStruct]) -> Void) {
let ref = Database.database().reference().child("AHPRatings").child(user.uid)
ref.observe(DataEventType.value, with: { snapshot in
guard let value = snapshot.value else { return }
do {
let ahpPrios = try FirebaseDecoder().decode(AHPPriorityStruct.self, from: value)
print(ahpPrios)
// MARK: - lets store the values in the actual constants :)
let ajkpXc = ahpPrios.ajkpXc
let ajkpXijr = ahpPrios.ajkpXijr
let ajkpXqpa = ahpPrios.ajkpXqpa
globaLajkpXc = ajkpXc ?? "no Value"
globaLajkpXijr = ajkpXijr ?? "no Value"
globaLajkpXqpa = ajkpXqpa ?? "no Value"
} catch let error {
print(error)
}
})
}
}
[1]: https://i.stack.imgur.com/VKxaE.png
You are calling UserService's ahpPref in your controller's viewWillAppear. BUT you are attempting to put your valueA (globaLajkpXc's value) to your label in your controller's viewDidLoad.
So what does that mean? Do you know which of these two controller's life cycle method gets called and when they do get called?
To solve your problem, have your label assigning value code
label1.text = globaLajkpXc
move in the completion block of your ahpPref (in the viewWillAppear).
Here's the Apple's documentation about the UIViewController's lifecycle: https://developer.apple.com/library/archive/referencelibrary/GettingStarted/DevelopiOSAppsSwift/WorkWithViewControllers.html
Also, below this line: globaLajkpXqpa = ajkpXqpa ?? "no Value"
add your completion call, like:
completion([ahpPrios]).
This should make my answer above work.

How to print the result of an if else statement into a specific text box

I'm a relatively new coder who wants to try out the iOS development language "Swift". The app I am creating is a weather app that will show the degrees in celsius and possibly some advice which is where the if statement comes in. However, I am encountering an issue with my code which I do not know how to solve.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var weatherLabel: UILabel!
#IBOutlet weak var quote: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let apiKey = "60e0655f404d7bf1"
let url = NSURL(string: "https://api.wunderground.com/api/eb56be2ac82d34b5/geolookup/conditions/forecast/q/Canada/Toronto.json")
let data = NSData(contentsOfURL: url!)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
let weather = json["current_observation"]!!["temp_c"]
weatherLabel.text = "\(weather!!)"
var quote = weather
var celsius = 20
if celsius >= quote {
print("Its cold outside, bring a jacket!")
}else{
print("Its hot outside, remember to drink water!") //if the weather in celsius is over 20 degrees, say ("Its hot outside, remember to drink water!")
}
} catch {
print("error serializing JSON: \(error)")
}
// Do any additional setup after loading the view, typically from a nib.
}
}
Does anyone know how I can set the quote in one specific text label and the degrees in the weatherLabel?
I also have an error saying that I can't convert AnyObject to an int.
Var quote = Int(weather) use this.

Completion Handler is not working in viewDidLoad?

I'm using this library in my app for banners. I am trying to get the Link by parsing the JSON.
The Images are are not showing in the slideshow view. If I press the slideshow view, after that everything works fine. I thought that there was some issue with my completion handler.
But I can't solve it yet :)
#IBOutlet weak var slideshow: ImageSlideshow!
var transitionDelegate: ZoomAnimatedTransitioningDelegate?
var Banner : [AlamofireSource] = []
override func viewDidLoad() {
super.viewDidLoad()
Banners { (imagesource) in
if imagesource != nil {
self.bannershow()
}
}
}
func Banners(completionHandler: ([AlamofireSource]?) -> ()) -> (){
Alamofire.request(.GET, "http://46.420.116.11/mobileapp/gps/api.php?rquest=get_banners")
.responseJSON{ response in
if let data = response.result.value{
let json = JSON(data)
let count = json["image_path"].count
for index in 0...count-1 {
let image :String = json["image_path"][index].stringValue
let source : AlamofireSource = AlamofireSource(urlString: image)!
self.Banner.append(source)
}
completionHandler(self.Banner)
}
}
}
func bannershow(){
self.slideshow.backgroundColor = UIColor.whiteColor()
self.slideshow.slideshowInterval = 2.0
self.slideshow.contentScaleMode = UIViewContentMode.ScaleToFill
self.slideshow.setImageInputs(self.Banner)
let recognizer = UITapGestureRecognizer(target: self, action: "click")
self.slideshow.addGestureRecognizer(recognizer)
}
func click() {
let ctr = FullScreenSlideshowViewController()
ctr.pageSelected = {(page: Int) in
self.slideshow.setScrollViewPage(page, animated: false)
}
ctr.initialPage = slideshow.scrollViewPage
ctr.inputs = slideshow.images
self.transitionDelegate = ZoomAnimatedTransitioningDelegate(slideshowView: slideshow);
ctr.transitioningDelegate = self.transitionDelegate!
self.presentViewController(ctr, animated: true, completion: nil)
}
You probably have a threading problem. There is no guarantee that the Banners completion handler is called on the main thread. You need to step out to the main thread explicitly before doing anything that touches your properties or (especially) the interface.
I think your problem might be that you're expecting the images to be available immediately but they need to be downloaded before, so they won't be available immediately after your viewDidLoad method finished. That's why you should probably configure your slideshow in the viewDidLoad and not in your bannershow() method. Something like this might be an improvement:
#IBOutlet weak var slideshow: ImageSlideshow!
var bannerImages : [AlamofireSource] = []
override func viewDidLoad() {
super.viewDidLoad()
slideshow.backgroundColor = UIColor.whiteColor()
slideshow.slideshowInterval = 2.0
slideshow.contentScaleMode = UIViewContentMode.ScaleToFill
let recognizer = UITapGestureRecognizer(target: self, action: "click")
slideshow.addGestureRecognizer(recognizer)
getBanners { imagesource in
self.showBanner()
}
}
func getBanners(completionHandler: ([AlamofireSource]?) -> ()) -> (){
Alamofire.request(.GET, "http://46.420.116.11/mobileapp/gps/api.php?rquest=get_banners")
.responseJSON{ response in
if let data = response.result.value{
let json = JSON(data)
let count = json["image_path"].count
for index in 0...count-1 {
let image :String = json["image_path"][index].stringValue
let source : AlamofireSource = AlamofireSource(urlString: image)!
self.bannerImages.append(source)
}
}
completionHandler(self.bannerImages)
}
}
func showBanner() {
slideshow.setImageInputs(bannerImages)
}
Move the code to viewWillAppear.
override func viewWillAppear(animated: Bool) {
Banners { (imagesource) in
if imagesource != nil {
self.bannershow()
}
}
}
func Banners(completionHandler: ([AlamofireSource]?) -> ()) -> (){
Alamofire.request(.GET, "http://46.420.116.11/mobileapp/gps/api.php?rquest=get_banners")
.responseJSON{ response in
if let data = response.result.value{
let json = JSON(data)
let count = json["image_path"].count
for index in 0...count-1 {
let image :String = json["image_path"][index].stringValue
let source : AlamofireSource = AlamofireSource(urlString: image)!
self.Banner.append(source)
}
completionHandler(self.Banner)
}
}
}
You are executing for loop in Banners fun
for index in 0...count-1 {
let image :String = json["image_path"][index].stringValue
let source : AlamofireSource = AlamofireSource(urlString: image)!
self.Banner.append(source)
}
Replace this code in some other method and place an Optional
var image :String? = json["image_path"][index].stringValue
or place an thumb image, That will make you confirm that image is downloaded successfully or not .
Let me know if it works
Thanks, Happy Coding
Maybe you don't see images because you update them in a secondary thread, you have to perform image update in main thread;
In swift ( performSelectorOnMainThread() is not available), you may use something like this :
dispatch_async(dispatch_get_main_queue(), {
myslideshow.updateimage();
})
Not really sure, but I am guessing that since your images need to get downloaded, they are nil when you call self.slideshow.setImageInputs(self.Banner), which internally sets the image from the list to an imageview which is added inside the scrollView. So one way I can think of is use SDWebImage to set the image to the imageView so that it updates the respective imageViews once the image is ready(downloaded). I think you will need to use it in the InputSource.swift class in the setToImageView(_:) method. You will have to check this though, this is the only possible problem i could think of that might be causing your issue.

How to make UIProgressView work in swift

I am trying to implement the UIProgressView!. I am downloading some data from a website and I am not wrapping my head around some of the fundamentals of how to write this code. I have the label called message which will be updated when the data is downloaded, but I want to show the progress of the data being downloaded.
import UIKit
class ViewController: UIViewController {
//They user types in the city they want to recieve the weather from
#IBOutlet weak var city: UITextField!
//The label that is being updated when the data finally reaches the phone
#IBOutlet weak var message: UILabel!
//The progress bar
#IBOutlet weak var downloadProgress: UIProgressView!
//My 'What's the weather?' button
#IBAction func buttonPressed(sender: AnyObject) {
//When you touch the button, the keyboard goes away
self.view.endEditing(true)
//setting the urlString to the address of the website, it will add the city that you type into the city text field
var urlString = "http://www.weather-forecast.com/locations/" + city.text.stringByReplacingOccurrencesOfString(" ", withString: "") + "/forecasts/latest"
//Setting the url to the urlString
var url = NSURL(string: urlString)
let task = NSURLSession.sharedSession().dataTaskWithURL(url!){(data, response, error) in
var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding)
var contentArray = urlContent!.componentsSeparatedByString("<span class=\"phrase\">")
var newContentArray = contentArray[1].componentsSeparatedByString("</span>")
//Updating the message text with the content that I want from the HTML source
self.message.text = (newContentArray[0] as! String)
}
task.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
self.downloadProgress.progress = 0.0
}
func makeMyProgressBarMoving {
var recievedData : Float
var expectedTotalSize : Float
var actual : Float = downloadProgress.progress
if (actual < 1) {
downloadProgress.progress = actual + (recievedData/expectedTotalSize)
[NSTimer .scheduledTimerWithTimeInterval(0.05, invocation: self, repeats: false)]
}
}
You cannot update the progress because you do not have any progress. You've implemented the wrong way of downloading the data. Use the other way - the one where you get delegate messages. One of them tells you the progress. In particular, you'll implement
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData {
Here you'll accumulate the data in an NSMutableData, and each time, you can compare the size of that accumulated data to the size of the expected total data, and thus you have the basis for updating the UIProgressView.

Resources