Apple TV gamepad buttons not triggering when I press them in the simulator - tvos

I am experiencing a problem in the Apple TV simulator. I have Xcode 9.4 and am using a Nimbus wireless controller. I have a menu screen for a game which does not register button clicks on the extended gamepad. The simulator sees the sticks and dpad and registers that when I use them but none of the buttons work. Here is the code I have. Here is the code. Could someone please review this and tell me why they think this does not work? Thanks, Greg
import UIKit
import GameController
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupControllerObservers()
connectControllers()
}
func setupControllerObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(connectControllers), name: NSNotification.Name.GCControllerDidConnect, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(controllerDisconnected), name: NSNotification.Name.GCControllerDidDisconnect, object: nil)
}
#objc func connectControllers() {
for controller in GCController.controllers() {
if (controller.extendedGamepad != nil && controller.playerIndex == .indexUnset) {
controller.playerIndex = .index1
controller.extendedGamepad?.valueChangedHandler = nil
setUpExtendedController(controller: controller)
} else if (controller.gamepad != nil && controller.playerIndex == .indexUnset) {
controller.playerIndex = .index1
controller.gamepad?.valueChangedHandler = nil
setUpStandardController(controller: controller)
}
}
}
enum stick {
case dPad
case leftThumbStick
case rightThumbStick
}
enum direction {
case up
case down
case left
case right
}
enum button {
case a
case b
case x
case y
case leftShoulder
case leftTrigger
case rightShoulder
case rightTrigger
}
func move(whichStick: stick, whichDirection: direction) {
print("moved")
}
func pressed(whichButton: button) {
print("pressed")
}
func setUpExtendedController(controller:GCController) {
controller.extendedGamepad?.valueChangedHandler = {
(gamepad: GCExtendedGamepad, element: GCControllerElement) in
if (gamepad.buttonA.isPressed) {
print("tseting button a pressed")
self.pressed(whichButton: button.a)
}
if (gamepad.buttonX.isPressed) {
self.pressed(whichButton: button.x)
}
if (gamepad.buttonY.isPressed) {
self.pressed(whichButton: button.y)
}
if (gamepad.rightShoulder.isPressed) {
self.pressed(whichButton: button.rightShoulder)
}
if (gamepad.rightTrigger.isPressed) {
self.pressed(whichButton: button.rightTrigger)
}
if (gamepad.leftShoulder.isPressed) {
self.pressed(whichButton: button.leftShoulder)
}
if (gamepad.leftTrigger.isPressed) {
self.pressed(whichButton: button.leftTrigger)
}
if (gamepad.leftThumbstick == element) {
if (gamepad.leftThumbstick.up.value > 0.2) {
self.move(whichStick: stick.leftThumbStick, whichDirection: direction.up)
} else if (gamepad.leftThumbstick.left.value > 0.2) {
self.move(whichStick: stick.leftThumbStick, whichDirection: direction.left)
} else if (gamepad.leftThumbstick.down.value > 0.2) {
self.move(whichStick: stick.leftThumbStick, whichDirection: direction.down)
} else if (gamepad.leftThumbstick.right.value > 0.2) {
self.move(whichStick: stick.leftThumbStick, whichDirection: direction.right)
}
} else if (gamepad.dpad == element) {
if (gamepad.dpad.down.isPressed == true) {
self.move(whichStick: stick.dPad, whichDirection: direction.down)
} else if (gamepad.dpad.left.isPressed == true) {
self.move(whichStick: stick.dPad, whichDirection: direction.left)
} else if (gamepad.dpad.right.isPressed == true) {
self.move(whichStick: stick.dPad, whichDirection: direction.right)
} else if (gamepad.dpad.up.isPressed == true) {
self.move(whichStick: stick.dPad, whichDirection: direction.up)
}
} else if (gamepad.rightThumbstick == element) {
if (gamepad.leftThumbstick.up.value > 0.2) {
self.move(whichStick: stick.rightThumbStick, whichDirection: direction.up)
} else if (gamepad.leftThumbstick.left.value > 0.2) {
self.move(whichStick: stick.rightThumbStick, whichDirection: direction.left)
} else if (gamepad.leftThumbstick.down.value > 0.2) {
self.move(whichStick: stick.rightThumbStick, whichDirection: direction.down)
} else if (gamepad.leftThumbstick.right.value > 0.2) {
self.move(whichStick: stick.rightThumbStick, whichDirection: direction.right)
}
}
}
}
func setUpStandardController(controller:GCController) {
controller.gamepad?.valueChangedHandler = {
(gamepad: GCGamepad, element:GCControllerElement) in
if (gamepad.dpad == element) {
if (gamepad.dpad.down.isPressed == true) {
self.move(whichStick: stick.dPad, whichDirection: direction.down)
} else if (gamepad.dpad.left.isPressed == true) {
self.move(whichStick: stick.dPad, whichDirection: direction.left)
} else if (gamepad.dpad.right.isPressed == true) {
self.move(whichStick: stick.dPad, whichDirection: direction.right)
} else if (gamepad.dpad.up.isPressed == true) {
self.move(whichStick: stick.dPad, whichDirection: direction.up)
}
} else if (gamepad.buttonA == element) {
self.pressed(whichButton: button.a)
//} else if (gamepad.buttonB == element) {
// self.pressed(whichButton: button.b)
} else if (gamepad.buttonX == element) {
self.pressed(whichButton: button.x)
} else if (gamepad.buttonY == element) {
self.pressed(whichButton: button.y)
} else if (gamepad.rightShoulder == element) {
self.pressed(whichButton: button.rightShoulder)
} else if (gamepad.leftShoulder == element) {
self.pressed(whichButton: button.leftShoulder)
}
}
}
#objc func controllerDisconnected() {
}
}

I figured out my problem. I needed to use buttonA == element instead of buttonA.isPressed.

Related

Fetched data is not showing in an IOS app

I'm building an ios app using SwiftUI for frontend and ts for API.
I've tried printing the fetched data out using List(results) { result in... and then Text(result.current_button.title) instead of showing the data I had a white space there.
Now I'm trying to solve the problem using ForEach(list.datas){ , but it's also now showing.
How do I print the fetched data on the app's screen?
import SwiftUI
class MainScreenVM: ObservableObject {
#Published var datas = [MainScreenStruct]()
init() {
loadData()
}
func loadData() {
print("Fetching started")
guard let url = URL(string: "http://localhost:3000/getMainScreen")
else {
print("Invalid URL")
return
}
let json: [String: Any] = ["grade": "12R",
"group": ["matemaatika": "G1",
"eesti keel": "G2"]]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let response = try? JSONDecoder().decode([MainScreenStruct].self, from: data) {
DispatchQueue.main.async {
//DispatchQueue.global().async {
self.datas = response
}
return
}
}
}.resume()
}
}
struct MainScreen: View{
#StateObject var list = MainScreenVM()
var body: some View {
ZStack{
LinearGradient(colors: [.pink, .orange], //if all lessons are finished or a weekend than fun color
startPoint: .topLeading, endPoint: .bottomTrailing)
.edgesIgnoringSafeArea(.all)
VStack {
VStack {
ProgressView(value: 2, total: 5) //value and total depends on the amount of lessons and lessons done
.padding()
HStack {
VStack(alignment: .leading) {
Text("Lessons done")
.font(.system(size: 20))
Label("3", systemImage: "house.fill") //instead of actual amount "300"
}
.padding()
Spacer()
VStack(alignment: .trailing) {
Text("Lessons left")
.font(.system(size: 20))
Label("2", systemImage: "flag.checkered.2.crossed")
}
.padding()
}
Spacer()
HStack {
VStack(alignment: .center) {
Button(action: {
print("VENE SUUR SÖÖGISAAL")
}) {
ForEach(list.datas) { item in
HStack{
Image(systemName: "brain.head.profile")
.font(.largeTitle)
Text(item.current_button.title)
}
.frame(minWidth: 0, maxWidth: .infinity)
.padding()
.foregroundColor(.white)
.background(LinearGradient(colors: [.indigo, .accentColor],
startPoint: .bottomTrailing, endPoint: .leading))
.cornerRadius(10)
.shadow(color: .gray, radius: 5.0)
.padding()
}
}
VStack() {
Text("Ends in {0} hours {20} minutes {4} seconds")
}
}
}
HStack {
VStack(alignment: .center) {
Button(action: {
print("VENE SUUR SÖÖGISAAL")
}) {
HStack{
Image(systemName: "books.vertical.fill")
.font(.largeTitle)
Text("Next lesson is {English}")
.font(.subheadline )
}
.frame(minWidth: 0, maxWidth: .infinity)
.padding()
.foregroundColor(.white)
.background(LinearGradient(colors: [.indigo, .accentColor],
startPoint: .bottomTrailing, endPoint: .leading))
.cornerRadius(10)
.shadow(color: .gray, radius: 5.0)
.padding()
}
Text("The lesson starts at {14:50}")
}
}
HStack {
VStack(alignment: .center) {
Button(action: {
print("VENE SUUR SÖÖGISAAL")
}) {
HStack{
Image(systemName: "fork.knife.circle.fill")
.font(.largeTitle)
Text("Lunch is in 1 hour 15 minutes 30 seconds")
.font(.subheadline )
}
.frame(minWidth: 0, maxWidth: .infinity)
.padding()
.foregroundColor(.white)
.background(LinearGradient(colors: [.indigo, .accentColor],
startPoint: .bottomTrailing, endPoint: .leading))
.cornerRadius(10)
.shadow(color: .gray, radius: 5.0)
.padding()
}
}
}
Spacer()
}
}
}
}
}
struct TimeLeft_Previews: PreviewProvider {
static var previews: some View {
MainScreen()
}
}
class VM: ObservableObject {
#Published var posts: [Post] = []
#Published var errorString:Bool = false
init() {
getDataFromAPI()
}
func getDataFromAPI() {
// Make a request to your localhost to retrieve the list of users
guard let url = URL(string: "http://localhost:3000/posts") else {
print("Invalid URL")
return
}
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("Error fetching users: \(error.localizedDescription)")
DispatchQueue.main.async {
self.errorString = true
}
return
}
guard let data = data else { return }
do {
// Parse the JSON data and create an array of User objects
let jsonDecoder = JSONDecoder()
let posts = try jsonDecoder.decode([Post].self, from: data)
DispatchQueue.main.async {
self.posts = posts
}
} catch {
print("Error parsing JSON: \(error.localizedDescription)")
}
}.resume()
}
}
This is my view model and fetch func. You can change the code as you need.

Mark Core Data entries as Favourites SWIFTUI

I am working on an app that stores posts from on-line Json to CoreData for offline content. It is a Real Estate Listings app where users sell and rent properties.
So far i accomplish to save fethed listings in CoreData but I can not implement "Add to Favourites" for the existing entries. I use NSPredicate to filter the listings types .in different views
I have created a entity "Listing" Core Data - Listing
And a "Favorite" entity Core Data - Favorites
My question is: How can i achieve "Add to Favourite"
Option A: Save the "is favourite" listing one more time in another Entity.
Option B: Create in the "Listing" Entity another "is favourite" property and keep it in Core Data as long as is favourite?
// Here is my Listing Model.swift
struct ListingModel: Hashable, Decodable, Encodable, Identifiable {
var id : Int
var title : String
var category : String
var name : String
var image : String
var publishdate : String
var saleprice : Int = 0
var rentprice : Int = 0
var listingtype : String
var latitude : Double!
var longitude : Double!
}
// JSONViewModel.swift
import SwiftUI
import CoreData
class JSONViewModel: ObservableObject {
#Published var listings: [ListingModel] = []
// #Published var tags :[Tags] = []
// saving Json to Core Data...
func saveData(contex: NSManagedObjectContext) {
listings.forEach { (data) in
let entity = Listing(context: contex)
entity.title = data.title
entity.name = data.name
entity.category = data.category
entity.image = data.image
entity.publishdate = data.publishdate
entity.tagline = data.tagline
entity.content = data.content
entity.coverimage = data.coverimage
entity.saleprice = Int64(truncating: NSNumber(value: data.saleprice))
entity.rentprice = Int64(truncating: NSNumber(value: data.rentprice))
entity.phone = data.phone
entity.email = data.email
entity.area = Int64(truncating: NSNumber(value: data.area))
entity.rooms = Int64(truncating: NSNumber(value: data.rooms))
entity.beds = Int64(truncating: NSNumber(value: data.beds))
entity.bathrooms = Int64(truncating: NSNumber(value: data.bathrooms))
entity.expires = data.expires
entity.adresa = data.adresa
entity.listingtype = data.listingtype
entity.latitude = Double(truncating: NSNumber(value: data.latitude))
entity.longitude = Double(truncating: NSNumber(value: data.longitude))
}
// }
// saving all pending data at once
do{
try contex.save()
print("success")
}
catch{
print(error.localizedDescription)
}
}
func fetchData(context: NSManagedObjectContext){
let url = "https://... my api adress"
var request = URLRequest(url: URL(string: url)!)
request.addValue("swiftui2.0", forHTTPHeaderField: "field")
let session = URLSession(configuration: .default)
session.dataTask(with: request) { (data, res, _) in
guard let jsonData = data else{return}
// check for errors
let response = res as! HTTPURLResponse
// checking by status code
if response.statusCode == 404 {
print("error Api Errror")
}
// fetching JSON Data ..
do {
let listings = try JSONDecoder().decode([ListingModel].self, from: jsonData)
DispatchQueue.main.async {
self.listings = listings
self.saveData(contex: context)
}
}
catch {
print(error.localizedDescription)
}
}
.resume()
}
// try to extend the function
func addListingToFavourites(favouritelisting:ListingModel) {
addRecordToFavourites(favouritelisting:favouritelisting.title)
}
func isListingFavourite(favouritelisting:ListingModel) -> Bool {
if let _ = fetchRecord(favouritelisting:favouritelisting.title) {
return true
}
return false
}
func removeListingFromFavourites(favouritelisting:ListingModel) {
removeRecordFromFavourites(favouritelisting:favouritelisting.title)
}
func toggleFavourite(favouritelisting:ListingModel) {
if isListingFavourite(favouritelisting: favouritelisting) {
removeListingFromFavourites(favouritelisting: favouritelisting)
}
else {
addListingToFavourites(favouritelisting: favouritelisting)
}
}
}
and i created also extension JSONViewModel:
extension JSONViewModel {
private func addRecordToFavourites(favouritelisting:String) {
guard let context = managedContext else {return}
if let record = fetchRecord(favouritelisting:favouritelisting) {
print("record \(record) already exists")
return
}
let entity = NSEntityDescription.entity(forEntityName: "Favourite",
in: context)!
let favourite = NSManagedObject(entity:entity, insertInto:context)
favourite.setValue(favouritelisting, forKeyPath:"favouritelisting")
do {
try context.save()
}
catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
self.changed = true
}
private func fetchRecord(favouritelisting:String) -> Favourite? {
guard let context = managedContext else {return nil}
let request = NSFetchRequest<Favourite>(entityName: "Favourite")
request.predicate = NSPredicate(format: "favouritelisting == %#", favouritelisting)
if let users = try? context.fetch(request) {
if users.count > 0 {
return users[0]
}
}
return nil
}
private func removeRecordFromFavourites(favouritelisting:String) {
guard let context = managedContext else {return}
if let record = fetchRecord(favouritelisting:favouritelisting) {
context.delete(record)
self.changed = true
}
}
}
::: Am i on the wright way? still i don't know it this what i should do!
Please find bellow Latest listingsView
import SwiftUI
struct latestListings: View {
#StateObject var jsonModel = JSONViewModel()
#Environment(\.managedObjectContext) var context
#FetchRequest(entity: Listing.entity(),
sortDescriptors:
[NSSortDescriptor(keyPath: \Listing.publishdate, ascending: false)])
var results : FetchedResults<Listing>
var textHeight: CGFloat = 60
var fullWidth: CGFloat = UIScreen.main.bounds.width
var cardWidthHalf: CGFloat = UIScreen.main.bounds.width / 2 + UIScreen.main.bounds.width / 3
var spacing: CGFloat = 10
var viewHeight: CGFloat = UIScreen.main.bounds.height / 2
#State private var isError = false
var body: some View {
VStack(alignment: .leading, spacing: 20) {
VStack(alignment: .leading, spacing: 10) {
HStack {
HStack {
Text("Latest Listings")
.modifier(textSectionTitle())
Spacer()
NavigationLink (destination: AllListingsVertical()) {
ViewMoreButton()
}.buttonStyle(PlainButtonStyle())
}
.padding(.trailing, 20)
}
Divider()
.modifier(dividerStyle())
HStack {
Image(systemName: "wand.and.stars.inverse")
.modifier(textSectionIcon())
Text("Manualy download listings to device storage. Useful for offline use.")
.modifier(textSectionTagline())
}
}
.padding(.top, 10)
.padding(.leading, 20)
.padding(.bottom, 0)
ScrollView(.horizontal, showsIndicators: false, content: {
HStack {
// checkin if core data exists
if results.isEmpty{
if jsonModel.listings.isEmpty{
HStack(alignment: .center) {
HStack(spacing: 10) {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: Color("dinamicPillsGrass")))
.scaleEffect(2, anchor: .center)
// fetching data
.onAppear(perform: {
jsonModel.fetchData(context: context)
})
}.frame(width: UIScreen.main.bounds.width)
}.modifier(cardHeight())
// when array is clear indicator appears
// as result data is fetched again
}
else{
HStack(spacing: 20) {
ForEach(jsonModel.listings,id: \.self){listing in
NavigationLink (destination: CardDetailView(listing: listing)) {
HStack {
CardViewOrizontal(listing: listing)
}
}.buttonStyle(PlainButtonStyle())
// display fetched Json Data..
}
}
}
}
else{
// results.prefix(?) unde ? cata articole sa arate
HStack(spacing: 20) {
ForEach(results.prefix(10)){listing in
NavigationLink (destination: CardDetailView(fetchedData: listing)) {
HStack {
CardViewOrizontal(fetchedData: listing)
}
}.buttonStyle(PlainButtonStyle())
}
}
.padding(.trailing, 15)
.padding(.leading, 15)
}
// update finish
}.padding(.top, 10)
.padding(.bottom, 10)
})
VStack(alignment: .center) {
Button(action: {
// clearing data in core data..
if Reachability.isConnectedToNetwork() {
//
do{
jsonModel.listings.removeAll()
results.forEach { (listing) in context.delete(listing) }
try context.save()
}
catch{
print(error.localizedDescription)
}
print("Network is connected")
self.isError = false
} else {
print("Network is not connected")
self.isError = true
}
}, label: {
HStack(alignment: .center) {
Image(systemName: "icloud.and.arrow.down")
.modifier(textSectionIcon())
Text("Update")
.modifier(textSectionTagline())
}
.padding(5)
.padding(.trailing, 5)
.background(Color("blueLeading"))
.cornerRadius(20)
.modifier(shadowPills())
}).alert(isPresented: $isError) {
Alert(title: Text("Network is not connected"),
message: Text("WiFi or Cellular not availible. You can still browse offline content!"),
dismissButton: .default(Text("OK")))
}
}.frame(width: fullWidth)
}
.padding(.top, 10)
.padding(.bottom, 60)
.frame(width: fullWidth)
.background(LinearGradient(gradient: Gradient(colors: [Color("dinamicGray1"), Color("dinamicGray2")]), startPoint: .top, endPoint: .bottom))
.cornerRadius(20)
.padding(.top, -50)
.modifier(shadowSection())
}
}
And CardDetailView
//
// CardDetailView.swift
// WebyCoreData
//
// Created by Marius Geageac on 20.12.2020.
//
import SwiftUI
import KingfisherSwiftUI
import MapKit
struct CardDetailView: View {
// noul liked
var fullWidth: CGFloat = UIScreen.main.bounds.width
var halfScreenH: CGFloat = UIScreen.main.bounds.height / 2
#ObservedObject var settingsVM = SettingsViewModel()
#State private var isVisible = false
var listing: ListingModel?
var fetchedData: Listing?
// Modifiers
var cardWidth: CGFloat = UIScreen.main.bounds.width
var imageWidth: CGFloat = UIScreen.main.bounds.width
/// map
var locationCoordinate: CLLocationCoordinate2D {
CLLocationCoordinate2D(
latitude: listing == nil ? fetchedData!.latitude : listing!.latitude,
longitude: listing == nil ? fetchedData!.longitude : listing!.longitude)
}
let paddingPills: CGFloat = 5
let textSizePills: CGFloat = 14
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 5) {
HStack {
Text(listing == nil ? fetchedData!.title! : listing!.title)
.modifier(textSectionTitle())
}
Divider()
.modifier(dividerStyle())
HStack {
Image(systemName: "info.circle")
.modifier(textSectionIcon())
Text(listing == nil ? fetchedData!.tagline! : listing!.tagline)
.modifier(textSectionTagline())
}
}
.padding(.top, 10)
.padding(.leading, 20)
.padding(.bottom, 0)
if self.fetchedData!.isFavorite == false {
Button(action: {
fetchedData!.isFavorite.toggle()
}) {
Image(systemName: "heart.circle")
.modifier(textSectionIcon())
}.padding()
}
else {
Button(action: {
fetchedData!.isFavorite.toggle()
}) {
Image(systemName: "heart.circle.fill")
.modifier(textSectionIcon())
}.padding()
}
}
}
}
import SwiftUI
struct Favorites: View {
#StateObject var jsonModel = JSONViewModel()
var cardWidth: CGFloat = UIScreen.main.bounds.width - 30
var fullWidth: CGFloat = UIScreen.main.bounds.width
// #StateObject var jsonModel = JSONViewModel()
#Environment(.managedObjectContext) var context
// Fetching Data From Core Data..
#FetchRequest(entity: Listing.entity(), sortDescriptors:
// [NSSortDescriptor(keyPath: \Listing.publishdate, ascending: false)])
[NSSortDescriptor(keyPath: \Listing.publishdate, ascending: false),],predicate: NSPredicate(format: "isFavourite == %#" , NSNumber(value: true)))
var results : FetchedResults<Listing>
var body: some View {
ScrollView(.vertical) {
VStack(alignment: .center) {
VStack(alignment: .center) {
LazyVStack(spacing: 20) {
ForEach(results){listing in
NavigationLink (destination: CardDetailView(fetchedData: listing)) {
VStack {
CardView(fetchedData: listing)
}.frame(width: UIScreen.main.bounds.width)
.modifier(cardHeight())
}.buttonStyle(PlainButtonStyle())
}
}
}
}.padding(.top, 20)
}
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
allListingsTitlePill() // Title
}
ToolbarItem(placement: .navigationBarTrailing){
HStack {
Button(action: {
}, label: {
Image(systemName: "heart.circle.fill")
.font(.system(size: 40, weight: .regular))
})
}
}
}
}
}
I would personally just add another property in your listings entity called isFavourite and set it to a boolean. set it initially to false.
Then when you are doing your fetch requests, you can only show favourites using a predicate like this.
let predicateIsFavourite = NSPredicate(format: "isFavourite == %#", NSNumber(value: true))
and in lists / ForEach, you display whether it is a favourite and use a button to toggle it being a favourite.
The toggle would just set the value of isFavourite to true (let me know if you would like some code for that but looking at your question, it seems like you know how to do that)

Exception when setting an optional binding to nil in SwiftUI after checking

I have a view with a State variable which is an Optional. I render the view by first checking if the optional variable is nil, and, if it is not, force unwrapping it and passing it into a subview using a Binding.
However, if I toggle the optional variable between a value and nil, the app crashes and I get a EXC_BAD_INSTRUCTION in the function BindingOperations.ForceUnwrapping.get(base:). How can I get the expected functionality of the view simply displaying the 'Nil' Text view?
struct ContentView: View {
#State var optional: Int?
var body: some View {
VStack {
if optional == nil {
Text("Nil")
} else {
TestView(optional: Binding($optional)!)
}
Button(action: {
if optional == nil {
optional = 0
} else {
optional = nil
}
}) {
Text("Toggle")
}
}
}
}
struct TestView: View {
#Binding var optional: Int
var body: some View {
VStack {
Text(optional.description)
Button(action: {
optional += 1
}) {
Text("Increment")
}
}
}
}
I found a solution that doesn't involve manually created bindings and/or hard-coded defaults. Here's a usage example:
if let unwrappedBinding = $optional.withUnwrappedValue {
TestView(optional: unwrappedBinding)
} else {
Text("Nil")
}
If you want, you could also provide a default value instead:
TestView(optional: $optional.defaulting(to: someNonOptional)
Here are the extensions:
protocol OptionalType: ExpressibleByNilLiteral {
associatedtype Wrapped
var optional: Wrapped? { get set }
}
extension Optional: OptionalType {
var optional: Wrapped? {
get { return self }
mutating set { self = newValue }
}
}
extension Binding where Value: OptionalType {
/// Returns a binding with unwrapped (non-nil) value using the provided `defaultValue` fallback.
var withUnwrappedValue: Binding<Value.Wrapped>? {
guard let unwrappedValue = wrappedValue.optional else {
return nil
}
return .init(get: { unwrappedValue }, set: { wrappedValue.optional = $0 })
}
/// Returns an optional binding with non-optional `wrappedValue` (`Binding<T?>` -> `Binding<T>?`).
func defaulting(to defaultValue: Value.Wrapped) -> Binding<Value.Wrapped> {
.init(get: { self.wrappedValue.optional ?? defaultValue }, set: { self.wrappedValue.optional = $0 })
}
}
Here is a possible approach to fix this. Tested with Xcode 12 / iOS 14.
The-Variant! - Don't use optional state/binding & force-unwrap ever :)
Variant1: Use binding wrapper (no other changes)
CRTestView(optional: Binding(
get: { self.optional ?? -1 }, set: {self.optional = $0}
))
Variant2: Transfer binding as-is
struct ContentView: View {
#State var optional: Int?
var body: some View {
VStack {
if optional == nil {
Text("Nil")
} else {
CRTestView(optional: $optional)
}
Button(action: {
if optional == nil {
optional = 0
} else {
optional = nil
}
}) {
Text("Toggle")
}
}
}
}
struct CRTestView: View {
#Binding var optional: Int?
var body: some View {
VStack {
Text(optional?.description ?? "-1")
Button(action: {
optional? += 1
}) {
Text("Increment")
}
}
}
}

how to pass profile image with other parameters in api using Alamofire 5 in swift 5

AF.request(urlString, method: .post, parameters: paramValue,encoding: URLEncoding.queryString, headers: ["accesstoken": "123456"]).responseJSON {
response in
switch response.result {
case .success(let JSON):
print("Login Response NSDictionary---->>",JSON as! NSDictionary)
delegate?.didSuccess(result: JSON as! NSDictionary, withID: "login")
break
case .failure(let error):
print("error----->>",error)
delegate?.didError(result: error, withID: "login")
}
}
Try this.It solves my problem
class func uploadImage(_ strURL: String, parameters: [String: Any]?,image: UIImage?,keyImage : String, success:#escaping apiSuccess, failure:#escaping apiFailure) {
print(parameters as Any)
var UrlFinal = ""
do
{
try UrlFinal = baseURL + strURL.asURL().absoluteString
}
catch{
}
Alamofire.upload(
multipartFormData: { MultipartFormData in
for (key, value) in (parameters)! {
print((key, value))
MultipartFormData.append((value as! String).data(using: String.Encoding.utf8)!, withName: key)
}
if image != nil{
guard let imageData = image!.jpegData(compressionQuality: 1) else { return }
MultipartFormData.append(imageData, withName: keyImage, fileName: "file1.jpeg", mimeType: "image/jpeg")
}
}, to: UrlFinal) { (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON { response in
if let res = response.result.value{
print(res)
Global.appDelegate.hideLoader()
success(res)
}else{
}
}
case .failure(let encodingError):
print(encodingError)
failure(encodingError)
}
}
}

how to updatePickerView Data according to previous picker view selection

I have 2 pickerView. one is showing courses and other is showing courses sections according to courses id(Response is going from Json) now the problem is when I choose course(lets say calculus) and then select the sectionPickerView it gives me list of corresponding sections(A,B,C,D) but when I change the course again to (English) the section PickerView still shows the same section and doesn't update sections according to Course Pickerview.
Here is my Code :
let coursesPicker = UIPickerView()
let sectionsPicker = UIPickerView()
var countryId = 0
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView == coursesPicker {
return GetCourses.instance.getCoursesInstance.count
} else {
return GetSectionService.sectionsServiceinstance.sectionModelInstance.count
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView == coursesPicker {
return GetCourses.instance.getCoursesInstance[row].courseName
} else {
return GetSectionService.sectionsServiceinstance.sectionModelInstance[row].sectionName
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == coursesPicker {
coursesTextField.text = GetCourses.instance.getCoursesInstance[row].courseName
countryId = GetCourses.instance.getCoursesInstance[row].id
self.callSectioApi(id: countryId)
self.coursesPicker.isHidden = true
} else {
sectionTextField.text = GetSectionService.sectionsServiceinstance.sectionModelInstance[row].sectionName
self.sectionsPicker.isHidden = true
}
self.view.endEditing(true)
}
function to update Url according to course Id
func callSectioApi(id : Int) {
let Idurl = String(id)
let url1 = getSectionUrl+Idurl
print(url1)
GetSectionService.sectionsServiceinstance.getSectionsName(url: url1) { (success) in
if success {
let status = GetSectionService.sectionsServiceinstance.status
if status == 400 {
print("400")
} else if status == 500 {
print("500")
} else if status == 404 {
print("404")
} else if status == 200 {
print("200")
self.sectionTextField.text = ""
self.sectionsPicker.reloadAllComponents()
} else {
print("Error")
}
} else {
let status = GetSectionService.sectionsServiceinstance.status
print(status)
}
}
}
You need to reload sectionPicker after course selection.
So, change your didSelect like below
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == coursesPicker {
coursesTextField.text = GetCourses.instance.getCoursesInstance[row].courseName
countryId = GetCourses.instance.getCoursesInstance[row].id
self.callSectioApi(id: countryId)
//Reload sectionPicker
self.sectionsPicker.reloadAllComponents()
self.sectionsPicker.selectRow(0, inComponent: 0, animated: false)
self.coursesPicker.isHidden = true
} else {
sectionTextField.text = GetSectionService.sectionsServiceinstance.sectionModelInstance[row].sectionName
self.sectionsPicker.isHidden = true
}
self.view.endEditing(true)
}