Different results between xcode and simulator - swift

in the picture a part of screenshot with a xcode printed code and the same result on an iPad simulator, can any one tell me why please?
here is the code
func loadLevel() {
var clueString = ""
var solutionString = ""
var letterBits = [String]()
if let levelFileURL = Bundle.main.url(forResource: "level\(level)", withExtension: ".txt") {
if let levelContents = try? String(contentsOf: levelFileURL) {
var lines = levelContents.components(separatedBy: "\n")
lines.shuffle()
for (index, line) in lines.enumerated() {
let parts = line.components(separatedBy: ": ")
let answer = parts[0]
let clue = parts[1]
clueString += "\(index + 1). \(clue)\n"
let solutionWord = answer.replacingOccurrences(of: "|", with: "")
solutionString += "\(solutionWord.count) letters\n"
solutions.append(solutionWord)
let bits = answer.components(separatedBy: "|")
letterBits += bits
}
}
}
print(clueString)
cluesLable.text = clueString.trimmingCharacters(in: .whitespacesAndNewlines)
answerLable.text = solutionString.trimmingCharacters(in: .whitespacesAndNewlines)
letterButtons.shuffle()
if letterButtons.count == letterBits.count {
for i in 0..<letterButtons.count {
letterButtons[i].setTitle(letterBits[i], for: .normal)
}
}
}

you need to remove labels line limitation in your code or your storyboard.
in code:
#IBOutlet weak var descriptionLabel: UILabel!{
didSet {
self.descriptionLabel.numberOfLines = 0
}
}

Related

Data from csv file won't show up when called in list on Swift

So I'm learning to import data from csv files to my swift project.
I'm trying to see everything is imported correctly by displaying some of the items in a list. However, even though I'm getting no errors at all, the list doesn't show up.
Can anyone help me out?
My csv setup code:
import Foundation
struct Leden: Identifiable {
var voorNaam: String = ""
var achterNaam: String = ""
var functie: String = ""
var id = UUID()
init (raw: [String]) {
voorNaam = raw[0]
achterNaam = raw[1]
functie = raw[2]
}
}
func loadCSV(from csvName: String) -> [Leden] {
var csvToStruct = [Leden]()
guard let filePath = Bundle.main.path(forResource: csvName, ofType: "csv") else {
return[]
}
var data = ""
do {
data = try String(contentsOfFile: filePath)
} catch {
print(error)
return[]
}
var rows = data.components(separatedBy: "\n")
let columnCount = rows.first?.components(separatedBy: ",").count
rows.removeFirst()
for row in rows {
let csvColumns = row.components(separatedBy: ",")
if csvColumns.count == columnCount {
let ledenStruct = Leden.init(raw: csvColumns)
csvToStruct.append(ledenStruct)
}
}
return csvToStruct
}
My code to make the csv items appear in a list:
struct PraesidiumView: View {
var individu = loadCSV(from: "Ledenlijst")
var body: some View {
NavigationView{
List(individu){Leden in
Text(Leden.voorNaam)
}
.navigationTitle("Praesidium")
}
}
}
try to implement this way, you also learn mvvm way.
class PraesidiumViewModel: ObservableObject {
#Public var ledens: [Leden] = []
func loadCSV() {
// ...
self.ledens = csvToStruct
}
}
struct PraesidiumView: View {
#StateObject var viewModel = PraesidiumViewModel()
var body: some View {
NavigationView {
List(viewModel.ledens){ leden in
Text(leden.voorNaam)
}
.navigationTitle("Praesidium")
}.onAppear() {
viewModel.loadCSV()
}
}
}
you could try something like this (untested) to read your csv data:
func loadCSV(from csvName: String) -> [Leden] {
var csvToStruct = [Leden]()
guard let filePath = Bundle.main.path(forResource: csvName, ofType: "csv") else {
return[]
}
var data = ""
do {
data = try String(contentsOfFile: filePath)
} catch {
print(error)
return []
}
var rows = data.components(separatedBy: "\n")
if let firstRow = rows.first {
rows.removeFirst()
for row in rows {
let csvColumns = row.components(separatedBy: ",")
if csvColumns.count >= 3 {
let ledenCol = Array(csvColumns[0..<3])
let ledenStruct = Leden(raw: ledenCol)
csvToStruct.append(ledenStruct)
}
}
}
return csvToStruct
}
So I find a solution.
I just restarted following the tutorial and this time, I gave all parameters the exact same name as they did in the tutorial and that worked.
So I just messed up because of probably a wrong name assigned to a certain parameter.

Displaying Data in ios Charts

I am creating an ios Chart that is based off of documents in Firestore. Here is my code:
import UIKit
import Charts
import Firebase
import FirebaseFirestoreSwift
import FirebaseAuth
class YearChartViewController: UIViewController, ChartViewDelegate {
enum valetTimeCategory: String{
typealias RawValue = String
case Year = "Year"
case Month = "Month"
case DaysOfWeeks = "Day1"
case CalendarDays = "Day2"
case Hour = "Hour"
}
var selectedCategory = valetTimeCategory.Year.rawValue
private var yearListener: ListenerRegistration!
#IBOutlet weak var segmentedController: UISegmentedControl!
var timeRetrieval = [timeData]()
var timeRetrievalYear = [yearTimeData]()
var barChart = BarChartView()
var pieChart = PieChartView()
lazy var companyUser = ""
#IBOutlet weak var localeIdLabel: UILabel!
private var timeDataCollection: CollectionReference!
var documentName1 = ""
override func viewDidLoad() {
super.viewDidLoad()
barChart.delegate = self
pieChart.delegate = self
localeIdLabel.text = companyUser
timeDataCollection = Firestore.firestore().collection("users").document(companyUser ).collection("time_data")
}
#IBAction func valetTimeCategory3(_ sender: Any) {
switch segmentedController.selectedSegmentIndex {
case 0:
selectedCategory = valetTimeCategory.Year.rawValue
case 1:
selectedCategory = valetTimeCategory.Month.rawValue
case 2:
selectedCategory = valetTimeCategory.DaysOfWeeks.rawValue
case 3: selectedCategory = valetTimeCategory.CalendarDays.rawValue
case 4: selectedCategory = valetTimeCategory.Hour.rawValue
default:
valetTimeCategory.Year.rawValue
}
self.yearListener.remove()
setListener()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setListener()
}
func setListener() {
barChart.frame = CGRect(x: 0, y: 0, width: 250, height: 250)
barChart.center = view.center
view.addSubview(barChart)
var entries = [BarChartDataEntry]()
yearListener = timeDataCollection.whereField(selectedCategory, isNotEqualTo: "Yaguay").order(by: selectedCategory).addSnapshotListener{ (querySnapshot, error) in
if let err = error {
debugPrint("Error fetching docs: \(err)")
} else {
self.timeRetrieval.removeAll()
guard let snap = querySnapshot else { return }
for document in snap.documents {
let FirebaseData = document.data()
let tiempoEs1 = FirebaseData["Year"] as? String ?? ""
let tiempoEs2 = FirebaseData["Month"] as? String ?? ""
let tiempoEs3 = FirebaseData["Day1"] as? String ?? ""
let tiempoEs4 = FirebaseData["Hour"] as? String ?? ""
let tiempoEs5 = FirebaseData["Day2"] as? String ?? ""
let documentIdThird = document.documentID
let newTimeRetrieval = timeData(timeContinuum1: tiempoEs1, timeContinuum2: tiempoEs2, timeContinuum3: tiempoEs3, timeContinuum4: tiempoEs4, timeContinuum5: tiempoEs5, documentId3: documentIdThird);
let newYearRetrieval = yearTimeData(timeContinuumYear: tiempoEs1)
self.timeRetrieval.append(newTimeRetrieval)
self.timeRetrievalYear.append(newYearRetrieval);
if self.selectedCategory == valetTimeCategory.Year.rawValue {
let q = Int(tiempoEs1)
let b = q?.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(q!), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries
)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
let format = NumberFormatter()
format.numberStyle = .decimal
let formatter = DefaultValueFormatter(formatter: format)
data.setValueFormatter(formatter)
self.barChart.legendRenderer.computeLegend(data: BarChartData(dataSet: set))
self.barChart.chartDescription?.text = "Years"
self.yearListener.remove()
}
if self.selectedCategory == valetTimeCategory.Month.rawValue {
let d = tiempoEs2.hashValue.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(d), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries, label: "\(self.selectedCategory)"
)
print(self.selectedCategory)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
self.yearListener.remove()
}
if self.selectedCategory == valetTimeCategory.DaysOfWeeks.rawValue {
let d = tiempoEs3.hashValue.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(d), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries, label: "\(self.selectedCategory)"
)
print(self.selectedCategory)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
self.yearListener.remove()
}
if self.selectedCategory == valetTimeCategory.CalendarDays.rawValue {
let q = Int(tiempoEs5)
let b = q?.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(b!), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries, label: "\(self.selectedCategory)"
)
print(self.selectedCategory)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
self.yearListener.remove()
}
if self.selectedCategory == valetTimeCategory.Hour.rawValue {
let q = tiempoEs4.hashValue.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(q), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries, label: "\(self.selectedCategory)"
)
print(self.selectedCategory)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
self.yearListener.remove()
}
}
}
}
}
#IBAction func monthButton1Tapped(_ sender: Any) {
self.companyUser = localeIdLabel.text!
performSegue(withIdentifier: "Month", sender: self)
}
#IBAction func logout(_ sender: Any) {
let auth = Auth.auth()
do {
try auth.signOut()
transitionToHome()
} catch let signOutError as Error {
debugPrint(signOutError)
}
}
func transitionToHome() {
let homeViewController = storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController)
view.window?.rootViewController = homeViewController
view.window?.makeKeyAndVisible()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! MonthChartViewController
vc.documentName = self.companyUser
}
}
Hopefully the random, nonsensical names aren't too distracting, but my problem is my Bar Chart isn't exactly displaying the right data. When I run the code, it displays:
Chart Image
There are 22 items (documents) in my collection. So it explicitly displays 22 objects, and if you count the numbers on each bar, the count on each bar is the correct number in each category (5 for 2020 and 17 for 2021). I don't know how to get my bar chart to explicitly display "17" and "5" for each category, please help if you know how to solve this.
timeRetrieval is appending additional entries each loop without clearing the previous entries. This is why the second bar has exactly the sum total.
You have a line self.timeRetrieval.removeAll() that is above the start of your for loop. Moving this line inside the loop should resolve this behavior.

Extracting data from csv file to put on UI table view

I was wondering if I could ask a question regarding csv/http posting. I want my data to update within my app after I pull the data from my github csv file, but when I do, it doesn't update within the app but just prints the numbers. What's wrong with my code? Thanks!
class NewStats: UITableViewController {
var didTapMenuType: ((NewMenu) -> Void)?
var Num2:String = "2"
#IBOutlet weak var MultnomahText: UILabel!
#IBOutlet weak var MultnomahView: UIProgressView!
override func viewDidLoad() {
let url = URL(string: "SampleUrl.csv")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
let str = (String(data: data, encoding: .utf8)!)
let fullNameArr = str.components(separatedBy: ",")
let Num1 = fullNameArr[0]
self.Num2 = fullNameArr[1]
let Num3 = fullNameArr[2]
let Num4 = fullNameArr[3]
let Num5 = fullNameArr[4]
let Num6 = fullNameArr[5]
let Num7 = fullNameArr[6]
let Num8 = fullNameArr[7]
let Num9 = fullNameArr[8]
let Num10 = fullNameArr[9]
print(Num1);
print(self.Num2);
print(Num3);
print(Num4);
print(Num5);
print(Num6);
print(Num7);
print(Num8);
print(Num9);
print(Num10);
}
task.resume()
super.viewDidLoad()
DispatchQueue.main.async {
self.tableView.reloadData()
}
print(self.Num2);
self.MultnomahText.text = "Multnomah:" + self.Num2
self.MultnomahView.setProgress(0.5, animated: true)
}
After the print(Num10)
DispatchQueue.main.async {
self.MultnomahText.text = "Multnomah:" + self.Num2
self.MultnomahView.setProgress(0.5, animated: true)
self.tableView.reloadData()
}
Hopefully this helps!

drawGlyphsForGlyphRange in Swift (Displaying Invisible characters). replaceGlyphAtIndex deprecated

I am trying to show Invisible characters using below class & func, and it is working fine.
But replaceGlyphAtIndex is deprecated in OS X 10.11 and we need to use setGlyhs()
setGlyphs(<#T##glyphs: UnsafePointer<CGGlyph>##UnsafePointer<CGGlyph>#>, properties: <#T##UnsafePointer<NSGlyphProperty>#>, characterIndexes: <#T##UnsafePointer<Int>#>, font: <#T##NSFont#>, forGlyphRange: <#T##NSRange#>)
But i am having difficulties on how to convert replaceGlyphAtIndex to setGlyphs.
Can any one suggest me how to convert below replaceGlyphAtIndex to setGlyphs()?
I tried as below but it is crashing.
let data = String(g).dataUsingEncoding(NSUTF8StringEncoding)
let cgG = UnsafePointer<CGGlyph>(data!.bytes)
self.setGlyphs(cgG, properties: nil, characterIndexes: UnsafePointer<Int>(bitPattern: characterIndex), font: font as! NSFont, forGlyphRange: NSMakeRange(glyphIndex, 1))
Can any one let me know whats going wrong in the above line of code?
class MyLayoutManager: NSLayoutManager {
override func drawGlyphsForGlyphRange(glyphsToShow: NSRange, atPoint origin: NSPoint) {
if let storage = self.textStorage {
let s = storage.string
let startIndex = s.startIndex
for glyphIndex in glyphsToShow.location ..< glyphsToShow.location + glyphsToShow.length {
let characterIndex = self.characterIndexForGlyphAtIndex(glyphIndex)
let ch = s[startIndex.advancedBy(characterIndex)]
switch ch {
case " ": //Blank Space
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("period")//("periodcentered")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
// let data = String(g).dataUsingEncoding(NSUTF8StringEncoding)
// let cgG = UnsafePointer<CGGlyph>(data!.bytes)
//
// self.setGlyphs(cgG, properties: nil, characterIndexes: UnsafePointer<Int>(bitPattern: characterIndex), font: font as! NSFont, forGlyphRange: NSMakeRange(glyphIndex, 1))
}
case "\n": //New Line
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("logicalnot")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
case newLineUniCodeStr:
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("logicalnot")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
default:
break
}
}
}
super.drawGlyphsForGlyphRange(glyphsToShow, atPoint: origin)
}
}
I found another way to display Glyphs. (Posting my code below as it may be useful to others)
override func drawGlyphsForGlyphRange(glyphsToShow: NSRange, atPoint origin: NSPoint) {
if let storage = self.textStorage {
let s = storage.string
let startIndex = s.startIndex
var padding:CGFloat = 0
for glyphIndex in glyphsToShow.location ..< glyphsToShow.location + glyphsToShow.length {
let characterIndex = self.characterIndexForGlyphAtIndex(glyphIndex)
if characterIndex < s.characters.count
{
var glyphStr = ""
let ch = s[startIndex.advancedBy(characterIndex)]
switch ch {
case " ": //Blank Space
glyphStr = periodCenteredUniCodeStr
case "\n": //New Line
glyphStr = lineBreakUniCodeStr
case newLineUniCodeStr:
glyphStr = lineBreakUniCodeStr
padding += 5
default:
break
}
var glyphPoint = self.locationForGlyphAtIndex(glyphIndex)
let glyphRect = self.lineFragmentRectForGlyphAtIndex(glyphIndex, effectiveRange: nil)
if glyphStr.characters.count > 0{
glyphPoint.x = glyphPoint.x + glyphRect.origin.x
glyphPoint.y = glyphRect.origin.y
NSString(string: glyphStr).drawInRect(NSMakeRect(glyphPoint.x, glyphPoint.y, 10, 10), withAttributes: nil)
}
}else{
print("Wrong count here")
}
}
}
super.drawGlyphsForGlyphRange(glyphsToShow, atPoint: origin)
}

Displaying Artwork for .MP3 file

I am trying to currently display the album artwork for a locally stored .MP3 track in an ImageView. Does anyone know how to fetch this artwork in Swift in order to accomplish this?
I have found this solution (iOS AVFoundation: How do I fetch artwork from an mp3 file?) but the code is written in Objective C. I simply want to grab the image embedded in my MP3 and display it in my ImageView.
I've looked at the API documentation for the MPMediaItemArtwork and found an example that also accomplishes what I am trying to accomplish in Objective C as well here(http://www.codeitive.com/0zHjkUjUWX/not-able-to-get-the-uiimage-from-mpmediaitempropertyartwork.html) but cannot come up with a solution. My code is as follows:
import UIKit
import AVFoundation
import MediaPlayer
class ViewController: UIViewController {
let audioPath:NSURL! = NSBundle.mainBundle().URLForResource("SippinOnFire", withExtension: "mp3")
#IBOutlet var artistImage: UIImageView!
#IBOutlet var trackLabel: UILabel!
#IBOutlet var artistLabel: UILabel!
#IBOutlet var sliderValue: UISlider!
var player:AVAudioPlayer = AVAudioPlayer()
#IBAction func play(sender: AnyObject) {
let audioInfo = MPNowPlayingInfoCenter.defaultCenter()
println(audioInfo)
player.play()
//println("Playing \(audioPath)")
let playerItem = AVPlayerItem(URL: audioPath)
let metadataList = playerItem.asset.metadata as! [AVMetadataItem]
for item in metadataList {
if let stringValue = item.value {
println(item.commonKey)
if item.commonKey == "title" {
trackLabel.text = stringValue as? String
}
if item.commonKey == "artist" {
artistLabel.text = stringValue as? String
}
if item.commonKey == "artwork" {
if let audioImage = UIImage(data: item.value as! NSData) {
let audioArtwork = MPMediaItemArtwork(image: audioImage)
println(audioImage.description)
}
}
}
}
}
#IBAction func pause(sender: AnyObject) {
player.pause()
}
#IBAction func stop(sender: AnyObject) {
player.stop()
player.currentTime = 0;
}
#IBAction func sliderChanged(sender: AnyObject) {
player.volume = sliderValue.value
}
override func viewDidLoad() {
super.viewDidLoad()
var error:NSError? = nil
player = AVAudioPlayer(contentsOfURL: audioPath!, error: &error)
player.volume = 0.5;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is a screen shot of my sample .mp3 file. As you can see there is indeed album artwork that is both visible in the "get info" section of Finder. I've also opened the .mp3 in my iTunes to make sure and have confirmed there is artwork in the "get info" section of it there as well as under the "artwork" tab.
However, when trying to use the commonKey to assign the image to my imageView I find that there is no commonKey for "artwork".
Thanks
Change your snippet of code into this (I already tested it):
I added println lines commented in places of interest, Feel free to uncomment in order to see what is happening.
for item in metadataList {
if item.commonKey == nil{
continue
}
if let key = item.commonKey, let value = item.value {
//println(key)
//println(value)
if key == "title" {
trackLabel.text = value as? String
}
if key == "artist" {
artistLabel.text = value as? String
}
if key == "artwork" {
if let audioImage = UIImage(data: value as! NSData) {
//println(audioImage.description)
artistImage.image = audioImage
}
}
}
}
UPDATE: A bit of clean up of this code
for item in metadataList {
guard let key = item.commonKey, let value = item.value else{
continue
}
switch key {
case "title" : trackLabel.text = value as? String
case "artist": artistLabel.text = value as? String
case "artwork" where value is NSData : artistImage.image = UIImage(data: value as! NSData)
default:
continue
}
}
UPDATE: For Swift 4
for item in metadataList {
guard let key = item.commonKey?.rawValue, let value = item.value else{
continue
}
switch key {
case "title" : trackLabel.text = value as? String
case "artist": artistLabel.text = value as? String
case "artwork" where value is Data : artistImage.image = UIImage(data: value as! Data)
default:
continue
}
}
edit/update Swift 4 or later:
import MediaPlayer
var nowPlayingInfo: [String: Any] = [:]
let playerItem = AVPlayerItem(url: url)
let metadataList = playerItem.asset.metadata
for item in metadataList {
switch item.commonKey {
case .commonKeyTitle?:
nowPlayingInfo[MPMediaItemPropertyTitle] = item.stringValue ?? ""
case .commonKeyType?:
nowPlayingInfo[MPMediaItemPropertyGenre] = item.stringValue ?? ""
case .commonKeyAlbumName?:
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = item.stringValue ?? ""
case .commonKeyArtist?:
nowPlayingInfo[MPMediaItemPropertyArtist] = item.stringValue ?? ""
case .commonKeyArtwork?:
if let data = item.dataValue,
let image = UIImage(data: data) {
nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { _ in image }
}
case .none: break
default: break
}
}
let audioInfo = MPNowPlayingInfoCenter.default()
audioInfo.nowPlayingInfo = nowPlayingInfo
Note: You will have to invoke beginReceivingRemoteControlEvents() otherwise it will not work on the actual device. You will also need to set your app Background Modes (Audio and AirPlay) and set your AVAudioSession category to AVAudioSessionCategoryPlayback and set it active:
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
Try this:
It appears that sometimes iOS 8 returns nil at first attempt of obtaining this info:
if let audioCenter = MPNowPlayingInfoCenter.defaultCenter(){
if let audioInfo = audioCenter.nowPlayingInfo{
if let artwork = audioInfo[MPMediaItemPropertyArtwork] as? MPMediaItemArtwork
{
var image: UIImage? = artwork.imageWithSize(artwork.bounds.size)
if image == nil {
image = artwork.imageWithSize(artwork.bounds.size);
}
if image != nil{
println("image loaded")
}
}
}
}