Post

Replies

Boosts

Views

Activity

Reply to Store Location from API into Array
Thanks for showing the definition. But in your shown code, self.nameArray.append(loc as! String) is commented out, so it does not make sense. Anyway, your code is full of bad practices and you should better update it. Please try the following code and tell us what you get from print statements. 				//#1 Start non-type identifiers with lower case letter 				var googleURLAPI = URLComponents(string: "https://maps.googleapis.com/maps/api/place/nearbysearch/json")! 				//#2 Better not call `addingPercentEncoding` yourself 				googleURLAPI.queryItems = [ 						URLQueryItem(name: "location", value: "\(origin.latitude),\(origin.longitude)"), 						URLQueryItem(name: "radius", value: "15000"), 						URLQueryItem(name: "type", value: "Fast Food"), 						URLQueryItem(name: "keyword", value: "Food"), 						URLQueryItem(name: "key", value: "API KEY"), 				] 				print(googleURLAPI.url!) 				 				var urlRequest = URLRequest(url: googleURLAPI.url!) 				 				urlRequest.httpMethod = "GET" 				 				let task = URLSession.shared.dataTask(with: urlRequest) { 						(data, response, error) in 						do { 								//making sure it actually has something 								if let error = error { 										throw error 								} 								//#3 Unwrap Optional safely with gurad-let 								guard let data = data else { 										print("data is nil") 										return // or throw some error 								} 								//For debugging, show response data as text 								print(String(data: data, encoding: .utf8) ?? "?") 								//#4 Better not use `try?`, use do-try-catch 								//#5 `mutableContainers` has no meaning in Swift 								//#6 Use Swift Dictionary type instead of `NSDictionary` 								guard let jsonDict = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] else { 										print("response data is not a JSON object") 										return // or throw some error 								} 								//setting jsonDict to read datta from url 								//#7 Use Swift Array type instead of `NSArray` 								guard let results = jsonDict["results"] as? [[String: Any]] else { 										print("`results` is not an Array of JSON object") 										return // or throw some error 								} 								//print("or here",LocArray) 								for result in results { 										if let location = result["location"] as? String { 												self.tester.append(location) 												//self.nameArray.append(location) 										} else { 												//#8 Show debug info handling else-case 												print("value for `location` not found or not string") 												return // or throw some error 										} 								} 								self.printNames() 								//print("json = \(jsonDict)") 						} catch { 								print(error) 								//#9 Better use `NSLocalizedString` for future internationalization 								let title = NSLocalizedString("There was an Error", comment: "") 								let message = NSLocalizedString("We encountered an error while trying to connect to Google. Try again later.", comment: "") 								let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) 								//#10 You can omit `handler:` when passing nil 								alert.addAction(UIAlertAction(title: "Okay!", style: .default)) 								self.present(alert, animated: true, completion: nil) 						} 				} 				task.resume() Generally, your original code disposes error info and ignores many unexpected cases, and also using too many forced unwrappings (!) and forced-castings (as!). Have you picked up this code from a very old article?
Topic: Programming Languages SubTopic: Swift Tags:
Apr ’21
Reply to Run something before another thing
OK. The basic principle of using async calls: If you want to Run something after acync thing, Do the next thing inside the completion handler. Your getDadJokes would look like this: func getDadJokes(completion: @escaping (Error?)-Void) { let collectionRef = self.db.collection("jokes") let documentRef = collectionRef.document("Dad Jokes") documentRef.getDocument(completion: { documentSnapshot, error in if let error = error { print(error) //Use `print(error)` rather than `print(error.localizedDescription)` completion(error) return } countDadJokes = (documentSnapshot?.data()!.count)! + 1 //print("count = \(count)") //Do the next thing inside the completion handler self.db.collection("jokes").document("Dad Jokes").addSnapshotListener { document, error in //check for error if let error = error { print(error) completion(error) return } //check if document exists if let doc = document, doc.exists { if let joke = doc.get("\(Int.random(in: 0...countDadJokes))") as? String { self.DadJokes = joke print("Joke: \(self.DadJokes)") //Do the next thing inside the completion handler completion(nil) return } else { completion(JokeError.noJoke) return } } else { completion(JokeError.noDocument) return } } }) } (Assuming you have reverted the changes to before introducing DispatchQueue.main.asyncAfter. The definition of JokeError will be shown later.) Your setRandomJoke (and JokeError) as follows: JokeError and setRandomJoke - https://developer.apple.com/forums/content/attachment/fa04c9a3-0678-4921-8df4-286f59f29fa1 And use it in this way: override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. if NetworkMonitor.shared.isConnected { Utilities.checkads(bannerView: bannerView, bannerViewHeight: bannerViewHeight) checkAppVersion() setRandomJoke { error in if let error = error { print(error) //Do things on error return } //Do the next thing inside the completion handler self.checkRandomJokeFail() Utilities.styleFilledButton(self.changeJoke) self.checkRecentCat() if Utilities.openNum == 1 { self.Welcome.text = "Welcome! Check out our app. In the categories section you will find all of our jokes!" } print("saveCat Defaults = \(Utilities.saveCat)") } } else { randomJoke.text = "Random Joke: Failed to connect to server" adLoadError.text = "Error Loading Ad" Utilities.checkToHideAds(bannerViewHeight: bannerViewHeight) } //These may not be `the next thing` recentCat.delegate = self recentCat.dataSource = self bannerView.rootViewController = self bannerView.delegate = self } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if NetworkMonitor.shared.isConnected { print("connected to internet") adLoadError.text = "Loading Ad" Utilities.checkads(bannerView: bannerView, bannerViewHeight: bannerViewHeight) bannerView.rootViewController = self checkRecentCat() recentCat.reloadData() if randomJoke.text == "Random Joke: " || randomJoke.text == "Random Joke: Failed to connect to server" { setRandomJoke { error in if let error = error { print(error) //Do things on error return } //Do the next thing inside the completion handler self.checkRandomJokeFail() Utilities.checkToHideAds(bannerViewHeight: self.bannerViewHeight) } } } else { print("not connected to internet") adLoadError.text = "Error Loading Ad" } } Your code still have many hidden things so I could not test this code. But hoping you can see what I mean by Do #3 in the completion handler of #2 or something like that.
Topic: UI Frameworks SubTopic: UIKit Tags:
Apr ’21
Reply to Math Problem, entering an answer
It will say right answer no matter what answer someone puts in. Thanks, that saves us much time to explore your code. You have 3 instance variables ranA, ranB and answer, but there is no code updating them. I guess you need to update two methods: func solveitproblem() { ranA = Int.random(in: 0...9) //- remove `let ` ranB = Int.random(in: 0...9) //- remove `let ` topProblem.text = String(ranA) botProblem.text = String(ranB) //youAnswer.text = String(answer) //- Do you really need this? let speakProblem = AVSpeechUtterance(string: "What is \(topProblem.text! + ", plus ," + botProblem.text!)") speakit.speak(speakProblem) } @IBAction func btncheckAnswer(_ sender: Any) { //↓ Get user's answer into `answer` guard let answer = Int(youAnswer.text ?? "") else { //Do something when user does not input an integer value... //... return } self.answer = answer if ranA + ranB == answer { correctAnswer() } else { wrongAnswer() } } (You usually do not use arc4random_uniform, but changing it is not mandatory.)
Topic: Programming Languages SubTopic: Swift Tags:
Apr ’21
Reply to Function with different signatures that can't coexist
Aren't functions with different signatures, supposed to be able to coexist? YES, when the functions are global: func nest1() - Int { print("nest1") return 3 } func nest1() - String { print("nest2") return "nest1" } Or they are methods: class MyClass { func nest1() - Int { print("nest1") return 3 } func nest1() - String { print("nest2") return "nest1" } } But, as for now, nested functions cannot be overloaded. Your code may work in the future version of Swift: Xcode 12.5 Beta 3 Release Notes - https://developer.apple.com/documentation/xcode-release-notes/xcode-12_5-beta-release-notes/ Updates in Xcode 12.5 Beta Swift Resolved Issues ・Function overloading now works in local contexts, making the following valid: ... Please get the latest beta of Xcode 12.5 and try by yourself.
Topic: Programming Languages SubTopic: Swift Tags:
Apr ’21
Reply to Make HTTP GET request?
What can be the issue? Each parameter in a URL needs to be properly escaped. Better try using URLComponents: var myUser: String = "myUser" var myPassword: String = "myPassword" var msg: String = "This is the message text" var urlComponents = URLComponents(string: "https://sveve.no/SMS/SendMessage")! urlComponents.queryItems = [ URLQueryItem(name: "user", value: myUser), URLQueryItem(name: "myPassword", value: myPassword), URLQueryItem(name: "msg", value: msg), URLQueryItem(name: "f", value: "json"), ] let url = urlComponents.url! print(url) //-https://sveve.no/SMS/SendMessage?user=myUser&myPassword=myPassword&msg=This%20is%20the%20message%20text&f=json
Topic: Programming Languages SubTopic: Swift Tags:
Apr ’21
Reply to Notification Center Help
I guess you need some storage independent from FavouritesVC. For example: class FavouritesManager { static let shared = FavouritesManager() var favArr: [CurrentPlayers] = [] func add(_ player: CurrentPlayers) { favArr.append(player) NotificationCenter.default.post( name: .passFavNotification, object: player ) } } HockeyDetailVC class HockeyDetailVC: UITableViewController { //... var item: CurrentPlayers? /* This object value I want in FaVC */ override func viewDidLoad() { super.viewDidLoad() } @IBAction func addToFav(_ sender: Any) { let alert = UIAlertController(title: "Favourite Added 💙", message: "\(name.text ?? "") is added to favourites", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default) {_ in if let favPlayer = self.item { FavouritesManager.shared.add(favPlayer) } }) self.present(alert, animated: true, completion: nil) print("Favourite button Pressed") } //... } FavouritesVC class FavouritesVC: UITableViewController { //var currentFav: CurrentPlayers? /*this is the variable I want to set my item too. */ var favArr: [CurrentPlayers] { FavouritesManager.shared.favArr } override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(handleFavNotification), name: .passFavNotification, object: nil) //Other settings... //... } @objc func handleFavNotification(notification: Notification) { tableView.reloadData() // Or something else... } //... }
Topic: Programming Languages SubTopic: Swift Tags:
Apr ’21
Reply to Class B inherit Class A that adopt ObservableObject, @Published do not work?
Isn't it the same issue announced as Resolved in iOS & iPadOS 14.5 beta 2? iOS & iPadOS 14.5 Beta 6 Release Notes - https://developer.apple.com/documentation/ios-ipados-release-notes/ios-ipados-14_5-beta-release-notes Updates in iOS & iPadOS 14.5 Beta 2 Combine Resolved in iOS & iPadOS 14.5 Beta 2 Using Published in a subclass of a type conforming to ObservableObject now correctly publishes changes. (71816443)
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Apr ’21
Reply to Notification Center Help
Yes you described my view hierarchy perfectly. Thanks for confirmation. (I assume this you is addressing @OOPer.) Then you are doing something I cannot understand. You say I'm trying to pass data forward from my HdVC to my FaVC with Notification Center using a button called addToFav, but your button action addToFav just presents the next VC FavouritesVC, it does not send anything (You may need to fix some parts as described in Claude31's reply, but it is another issue than does not seem to pass my data.) Your FavouritesVC would try to send currentFav from FavouritesVC to HockeyDetailVC with Notification Center if currentFav is not nil (currentFav in FavouritesVC is always nil in viewDidLoad(), so it does nothing.) I first though that the code NotificationCenter.default.post... is sort of a test of passing something from FavouritesVC to HockeyDetailVC with Notification Center, but your description confuses me. If you want to send something with Notification Center from HockeyDetailVC to FavouritesVC, you need to call NotificationCenter.default.post... inside the method of HockeyDetailVC, after FavouritesVC get ready to receive it. Or your description from my HdVC to my FaVC is just a simple mistake and you want to pass something from FavouritesVC to HockeyDetailVC?
Topic: Programming Languages SubTopic: Swift Tags:
Apr ’21
Reply to Integrate Metal/ObjC Tutorial into SwiftUI
This what I have done: import SwiftUI import MetalKit struct MyMtkView: UIViewRepresentable { typealias UIViewType = MTKView var mtkView: MTKView init() { self.mtkView = MTKView() } func makeCoordinator() - Coordinator { Coordinator(self, mtkView: mtkView) } func makeUIView(context: UIViewRepresentableContextMyMtkView) - MTKView { mtkView.delegate = context.coordinator mtkView.isPaused = false mtkView.preferredFramesPerSecond = 60 mtkView.enableSetNeedsDisplay = false mtkView.framebufferOnly = true return mtkView } func updateUIView(_ uiView: MTKView, context: UIViewRepresentableContextMyMtkView) { // } class Coordinator : AAPLRenderer { var parent: MyMtkView init(_ parent: MyMtkView, mtkView: MTKView) { self.parent = parent guard let metalDevice = MTLCreateSystemDefaultDevice() else { fatalError("Metal is not supported on this device") } mtkView.device = metalDevice super.init(metalKitView: mtkView) mtkView.framebufferOnly = false mtkView.clearColor = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 0) mtkView.drawableSize = mtkView.frame.size mtkView.enableSetNeedsDisplay = true self.mtkView(mtkView, drawableSizeWillChange: mtkView.drawableSize) } } } You need to create a device using MTLCreateSystemDefaultDevice as in the thread you have shown You need to initialize AAPLRenderer (Rendere?) with passing mtkView
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’21
Reply to Mac OS version outdated for WWDC 2021 challenge
The Swift Student Challenge page - https://developer.apple.com/wwdc21/swift-student-challenge/ clearly states this as a requirement: Your Swift playground must be built with and run on Swift Playgrounds 3.4.1 on iPadOS 14.4.2, Swift Playgrounds 3.4.1 on macOS 11.2.3, or Xcode 12.4 on macOS 11.2.3. If it runs on iPadOS, it must be optimized to display properly on all models of iPad Pro. I think you can develop the Swift Playground using your Mac and borrow a Mac of your friends when building the app and submitting it to Apple.
Topic: Programming Languages SubTopic: Swift Tags:
Mar ’21
Reply to How to get single object JSON API in SwiftUI
I need to edit it to be for a single object.  Sorry, I have been missing your words my old code the gets a multi-object array. But you just need to pass the struct type to decode(_:from:) instead of Array type: For example: struct SingleObject: Codable { var sunRise: String //... } enum ApiError: Error { case dataIsNil } class ApiCall { func getSingleObject(completion:@escaping (ResultSingleObject, Error) - ()) { guard let url = URL(string: "...") else { return } URLSession.shared.dataTask(with: url) { (data, _, error) in if let error = error { print(error) completion(.failure(error)) return } guard let data = data else { print("data is nil") completion(.failure(ApiError.dataIsNil)) return } do { let singleObject = try JSONDecoder().decode(SingleObject.self, from: data) //- print(singleObject) DispatchQueue.main.async { completion(.success(singleObject)) } } catch { print(error) completion(.failure(error)) } } .resume() } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’21