Post

Replies

Boosts

Views

Activity

Dealing with IAP Purchase Restore
Do you let your users restore their IAP purchases with or without history of purchases? I don't. And it had not been a problem in the past 10 years or so till two days ago when the reviewer rejected my new iOS software submission. He or she said that it was a bug since the Restore button is disabled. I saw the screenshot he or she gave me in which it was obvious that the reviewer had not made a purchase. For me, I cannot think of a reason why one with no history of purchases should be allowed to proceed and restore purchases. I don't even know what the reviewer is trying to restore. So far, the reviewer doesn't buy my explanation or seems to ignore me. What do you think? Do you let them go lucky by accident? By the way, this is a non-consumable IAP product.
4
0
89
Aug ’25
App Record Creation Error with Organizer
I've been trying to send an archive with Organizer to iTunes Connect. It's not my first time. I've been doing it for more than a decade. Anyway, when I try to send a package for my new macOS application, Organizer gives me two error messages that I have never seen before. App Record Creation Error App Record Creation failed due to an invalid attribute. The SKU you entered has already been used. App Record Creation Error App Record Creation failed due to request containing an attribute already in use. The app name you entered is already being used for another app in your account. If you would like to use the name for this app you will need to submit an update to your other app to change the name, or remove it from App Store Connect. An odd thing is that, as shown in the screenshot below, Organizer demands that I enter an application name and SKU manually. I've entered the exactly same ones from the App Store Connect page. I didn't see this step on Organizer last month. I'm using a new SKU for this submission. And I don't have an existing application at iTunes Connect with the same application name. I guess it's the same issue that has been reported here.. I have no pending contract issues. How do I send an archive without errors? My Xcode version is Version 16.4 (16F6). Thanks.
4
0
244
Sep ’25
Value of type 'UIView?' has no member 'isEnabled'
I have the following lines of code in practicing Combine. import UIKit import Combine class ViewController: UIViewController { // MARK: - Variables var cancellable: AnyCancellable? @Published var segmentNumber: Int = 0 // MARK: - IBOutlet @IBOutlet weak var actionButton: UIButton! // MARK: - IBAction @IBAction func segmentChanged(_ sender: UISegmentedControl) { segmentNumber = sender.selectedSegmentIndex } // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() cancellable = $segmentNumber.receive(on: DispatchQueue.main) .assign(to: \.isEnabled, on: actionButton) } } I get an error at .assign that says Value of type 'UIView?' has no member 'isEnabled' What am I doing wrong? Thank you.
3
0
2.5k
Aug ’21
Toggling Values on EnvironmentValue (EditMode)
I have the following lines of code for showing a list of friends. import SwiftUI struct ContentView: View { @State var users = ["Susan", "Kate", "Natalie", "Kimberly", "Taylor", "Sarah", "Nancy", "Katherine", "Nicole", "Linda", "Jane", "Mary", "Olivia", "Barbara"] @State var editMode = EditMode.inactive var body: some View { NavigationView { List { ForEach(users, id: \.self) { user in Text(user) } } .navigationBarTitle("Friends") .environment(\.editMode, $editMode) .navigationBarItems(leading: Button("Edit", action: { if self.editMode == .active { self.editMode = .inactive } else { self.editMode = .active } })) } } } If you see the code at the bottom, I have four lines just in order to change the value of editMode. Does SwiftUI have something like showDetails.toggle() where showDetails is a Boolean variable? Muchos thankos.
3
0
562
Sep ’21
Combine with UITableView
Hello, I'm trying to work out a simple example to fill table view data with Combine. The following is what I have. import Foundation struct MyModel: Decodable { let id: String let type: String } import UIKit import Combine class APIClient: NSObject { var cancellable: AnyCancellable? let sharedSession = URLSession.shared func fetchData(urlStr: String, completion: @escaping ([MyModel]?) -> Void) { guard let url = URL(string: urlStr) else { return } let publisher = sharedSession.dataTaskPublisher(for: url) cancellable = publisher.sink(receiveCompletion: { (completion) in switch completion { case .failure(let error): print(error) case .finished: print("Success") } }, receiveValue: { (result) in let decoder = JSONDecoder() do { let post = try decoder.decode([MyModel].self, from: result.data) completion(post) } catch let error as NSError { print("\(error)") completion(nil) } }) } } import Foundation class ViewModel: NSObject { @IBOutlet var apiClient: APIClient! var dataModels = [MyModel]() func getGitData(completion: @escaping () -> Void) { let urlStr = "https://api.github.com/repos/ReactiveX/RxSwift/events" apiClient.fetchData(urlStr: urlStr) { (models) in if let myModels = models { self.dataModels = myModels.map { $0 } } completion() } } } import UIKit import Combine class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { // MARK: - Variables var cancellable: AnyCancellable? @IBOutlet var viewModel: ViewModel! @Published var models = [MyModel]() // MARK: - IBOutlet @IBOutlet weak var tableView: UITableView! // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() viewModel.getGitData { self.models = self.viewModel.dataModels } cancellable = $models.sink(receiveValue: { (result) in DispatchQueue.main.async { [weak self] in guard let strongSelf = self else { return } strongSelf.tableView.reloadData() } }) } // MARK: - TableView func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return models.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell") let dataModel = models[indexPath.row] cell?.textLabel?.text = dataModel.id cell?.detailTextLabel?.text = dataModel.type return cell! } } I'm not quite comfortable with the lines of code under my view controller (ViewController) in using Combine. How can I make them better? Muchos thankos.
3
0
3.6k
Oct ’22
Keeping Track of Text Changes over Two Text Fields
I'm still a beginner in using Combine. I practice it on and off. Anyway, I have a view model to see changes in two text fields in my view controller as follows. // ViewModel // import Foundation import Combine class LoginViewModel { var cancellable = [AnyCancellable]() init(username: String, password: String) { myUsername = username myPassword = password } @Published var myUsername: String? @Published var myPassword: String? func validateUser() { print("\(myUsername)") print("\(myPassword)") } } And my view controller goes as follows. // ViewController // import UIKit import Combine class HomeViewController: UIViewController { // MARK: - Variables var cancellable: AnyCancellable? // MARK: - IBOutlet @IBOutlet var usernameTextField: UITextField! @IBOutlet var passwordTextField: UITextField! // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() cancellable = NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: usernameTextField) .sink(receiveValue: { result in if let textField = result.object as? UITextField { if let text = textField.text { let loginViewModel = LoginViewModel(username: text, password: "") loginViewModel.validateUser() } } }) } } So I use NSNotification as a publisher to see text changes over one of the text fields. And I cannot see text changes over two of them at the same time. Is there a better approach in seeing text changes over two text fields at the same time using Combine? Muchos thankos.
3
0
2.2k
Oct ’21
Using URLSession in Combine
I'm trying to figure out how to use URLSession with the Combine framework. I have a class that is to fetch data as follows. import UIKit import Combine class APIClient: NSObject { var cancellables = [AnyCancellable]() @Published var models = [MyModel]() func fetchData(urlStr: String) -> AnyPublisher<[MyModel], Never> { guard let url = URL(string: urlStr) else { let subject = CurrentValueSubject<[MyModel], Never>([]) return subject.eraseToAnyPublisher() } let subject = CurrentValueSubject<[MyModel], Never>(models) URLSession.shared.dataTaskPublisher(for: url) .map { $0.data } .decode(type: [MyModel].self, decoder: JSONDecoder()) .replaceError(with: []) .sink { posts in print("api client: \(posts.count)") self.models = posts } .store(in: &cancellables) return subject.eraseToAnyPublisher() } } I then have a view model class that is to deliver data for my view controller as follows. import Foundation import Combine class ViewModel: NSObject { @IBOutlet var apiClient: APIClient! var cancellables = Set<AnyCancellable>() @Published var dataModels = [MyModel]() func getGitData() -> AnyPublisher<[MyModel], Never> { let urlStr = "https://api.github.com/repos/ReactiveX/RxSwift/events" let subject = CurrentValueSubject<[MyModel], Never>(dataModels) apiClient.fetchData(urlStr: urlStr) .sink { result in print("view model: \(result.count)") self.dataModels = result }.store(in: &cancellables) return subject.eraseToAnyPublisher() } } My view controller has an IBOutlet of ViewModel. import UIKit import Combine class ViewController: UIViewController { // MARK: - Variables var cancellables = [AnyCancellable]() @IBOutlet var viewModel: ViewModel! // MARK: - IBOutlet @IBOutlet weak var tableView: UITableView! // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() viewModel.getGitData() .sink { posts in print("view controller: \(posts.count)") } .store(in: &cancellables) } } If I run it, it seems that ViewModel returns 0 without waiting for APIClient to return data. And the view controller doesn't wait, either. What am I doing wrong? Can I do it without using the completion handler? In case you need to know what MyModel is, it's a simple struct. struct MyModel: Decodable { let id: String let type: String } Muchos thanks
3
0
1.7k
Nov ’21
Publishers.CombineLatest in SwiftUI
I've been using Combine with UIKit and Cocoa. The following is a simple example. import UIKit import Combine class ViewController: UIViewController { // MARK: - Variables private var cancellableSet: Set<AnyCancellable> = [] @Published var loginText: String = "" @Published var passwordText: String = "" // MARK: - IBOutlet @IBOutlet weak var loginField: UITextField! @IBOutlet weak var passwordField: UITextField! // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: loginField) .sink { result in if let textField = result.object as? UITextField { if let text = textField.text { self.loginText = text } } } .store(in: &cancellableSet) NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: passwordField) .sink { result in if let textField = result.object as? UITextField { if let text = textField.text { self.passwordText = text } } } .store(in: &cancellableSet) Publishers.CombineLatest($loginText, $passwordText) .sink { (result0, result1) in if result0.count > 3 && result1.count > 3 { print("You are good") } else { print("No way!!!") } } .store(in: &cancellableSet) } } Now, I want to use Combine with SwiftUI. The following is SwiftUI equivalent, so far. import SwiftUI import Combine struct ContentView: View { @State var anycancellables = Set<AnyCancellable>() @State var userText: String = "" @State var passText: String = "" @State var canSave: Bool = false var body: some View { ZStack { VStack { Color.white }.onTapGesture { UIApplication.shared.endEditing() } VStack { TextField("Username", text: $userText) { }.onChange(of: userText) { newValue in } SecureField("Password", text: $passText) { }.onChange(of: passText) { newValue in } Spacer() .frame(height: 20.0) Button("Save") { print("Saved...") } .foregroundColor(canSave ? Color.black : Color.gray) .font(.system(size: 32.0)) .disabled(!canSave) }.padding(.horizontal, 20.0) } } } So where does Combine fit into the code? I want to enable the Save button if text counts of loginText and passwordText are both greater than 3, which is done at the top with UIKit. Muchos thankos.
3
0
2.2k
Jan ’22
Using Subclassed UIViewController
I'm trying to subclass UIViewController. And I've written the following. import UIKit class BaseViewController: UIViewController { let titleText: String init(titleText: String) { self.titleText = titleText super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { self.titleText = "" super.init(coder: aDecoder) setup() } override func viewDidLoad() { super.viewDidLoad() } // MARK: - Setup func setup() { print("GGG: \(titleText)") let navBar = navigationController!.navigationBar navBar.barTintColor = UIColor.yellow let atext = NSMutableAttributedString(string: titleText) atext.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.black, range: NSMakeRange(0, atext.length)) atext.addAttribute(NSAttributedString.Key.strokeColor, value: UIColor.gray, range: NSMakeRange(0, atext.length)) atext.addAttribute(NSAttributedString.Key.strokeWidth, value: NSNumber.init(value: -1.0), range: NSMakeRange(0, atext.length)) let titleLabel: UILabel = UILabel(frame: CGRect(origin: CGPoint(x: 15.0, y: 0), size: CGSize(width: 320.0 - 120.0, height: 44.0))) titleLabel.attributedText = atext titleLabel.textAlignment = NSTextAlignment.center titleLabel.font = UIFont(name: "Helvetica", size: 24.0) self.navigationItem.titleView = titleLabel } } And I subclass it with a view controller named HomeViewController as follows. import UIKit class HomeViewController: BaseViewController { override init(titleText: String) { super.init(titleText: "Jim") } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func viewDidLoad() { super.viewDidLoad() } } But the setup method in BaseViewController never gets the titleText variable ("Jim") from HomeViewController. What am I doing wrong? Thanks.
Topic: UI Frameworks SubTopic: UIKit Tags:
3
0
666
Feb ’22
Telling a View to show a Dialog from Another
I was quite active in writing code in SwiftUI several months ago. I've forgotten how to use an ObservedObject object to channel a variable between two Views. Anyway, I need to show a dialog over ContentView when I tap a button that is shown over another (RightView). The following is my code. // ContentView.swift // import SwiftUI class ObserveMonster: ObservableObject { @Published var showDialog = false } struct ContentView: View { @ObservedObject var observeManiac: ObserveMonster var body: some View { GeometryReader { geo in ZStack { HStack(spacing: 0.0) { LeftView() .frame(width: geo.size.width / 2.0, height: geo.size.height, alignment: .leading) RightView() .frame(width: geo.size.width / 2.0, height: geo.size.height, alignment: .trailing) } ShowDialogView(isShowing: observeManiac.showDialog) { } .frame(width: 500, height: 600, alignment: .center) .cornerRadius(10.0) } } } } struct ShowDialogView<Content: View>: View { let isShowing: Bool @ViewBuilder let content: () -> Content var body: some View { Group { if isShowing { Color.blue } } .animation(.default, value: isShowing) } } // RightView.swift // import SwiftUI struct RightView: View { @StateObject var observeManiac = ObserveMonster() var body: some View { ZStack { Color.red Button { observeManiac.showDialog.toggle() } label: { Text("Tap me") .font(.largeTitle) } } } } When I tap the button, the dialog (ShowDialogView) is no show. Does anybody now what I'm doing wrong? Thanks a million.
3
0
566
Mar ’22
Deleting a View Instance with the Tap of a Button
I have a simple project where I have a UUID string followed by a tap button as shown below. If one taps the Add me, the app will list a new instance of a View (KeywordRow). The following is what I have. import SwiftUI struct ContentView: View { @ObservedObject var monster: Monster var body: some View { VStack { Button { monster.items.append(Keyword()) } label: { Text("Add me!") }.padding(.vertical, 10.0) ForEach($monster.items) { item in KeywordRow(id: item.id) } } } } // MARK: - ObservableObject class Monster: ObservableObject { @Published var items = [Keyword]() } // MARK: - Keyword struct Keyword: Identifiable { var id = UUID() } struct KeywordRow: View { @Binding var id: UUID var body: some View { VStack { HStack { Text("ID: \(id)") Button { /* ------ Delete ------ */ } label: { Text("Delete") } } } } } My question is how I can let the app delete the corresponding instance when I tap the Delete button? I have an ObservedObject variable, which I haven't used. Thanks.
3
0
1.4k
Apr ’22
TextField Binding
I have an array of a model with just a single string with which I want to create instances of TextField. And I get an error for the TextField string binding. I know that is wrong. But how can fix it so that I can use textModel.name as a Binding? import SwiftUI struct ContentView: View { @State var textModels = [TextModel]() var body: some View { HStack { ForEach(textModels.indices, id: \.self) { index in let textModel = textModels[index] TextField("", text: textModel.name) // <----- Cannot convert value of type 'String' to expected argument type 'Binding<String>' } }.background(Color.green) .onAppear { textModels.append(TextModel(name: "Jim Thorton")) textModels.append(TextModel(name: "Susan Murphy")) textModels.append(TextModel(name: "Tom O'Donnell")) textModels.append(TextModel(name: "Nancy Smith")) } } } struct TextModel: Hashable { let name: String } Thanks.
3
0
1.1k
Apr ’22
AVCaptureSession startRunning crash
I have revisited AVCaptureSession in UIKit to capture a snapshot with the FaceTime camera. And my sample app will crash when AVCaptureSession starts running. Does anyone know how to fix it? The console says the following purple warning. -[AVCaptureSession startRunning] should be called from background thread. Calling it on the main thread can lead to UI unresponsiveness import UIKit import AVFoundation class CaptureViewController: UIViewController, AVCapturePhotoCaptureDelegate { var captureSession: AVCaptureSession! var cameraDevices: AVCaptureDevice! var imagePhotoOutput: AVCapturePhotoOutput! enum CameraCase { case front case back } // MARK: - IBAction @IBAction func selectTapped(_ sender: UIButton) { snapPicture() } // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) prepareCamera(cameraCase: .front) } // MARK: - Camera func prepareCamera(cameraCase: CameraCase) { /* removing existing layers */ if let sublayers = self.view.layer.sublayers { for sublayer in sublayers { if sublayer.isKind(of: AVCaptureVideoPreviewLayer.self) { sublayer.removeFromSuperlayer() } } } /* creating a capture session */ captureSession = AVCaptureSession() if cameraCase == .front { guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .back).devices.first else { return } let videoInput = try? AVCaptureDeviceInput(device: device) if captureSession.canAddInput(videoInput!) { captureSession.addInput(videoInput!) imagePhotoOutput = AVCapturePhotoOutput() // setting output destination captureSession.addOutput(imagePhotoOutput) // adding photo output to session } } else { guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .front).devices.first else { return } let videoInput = try? AVCaptureDeviceInput(device: device) if captureSession.canAddInput(videoInput!) { captureSession.addInput(videoInput!) imagePhotoOutput = AVCapturePhotoOutput() // setting output destination captureSession.addOutput(imagePhotoOutput) // adding photo output to session } } /* creating a capture layer */ let captureVideoLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session: captureSession) captureVideoLayer.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height) captureVideoLayer.videoGravity = AVLayerVideoGravity.resizeAspect /* adding video capture layer to the view layer */ self.view.layer.addSublayer(captureVideoLayer) /* starting capture session */ captureSession.startRunning() //<<<<<<<<<<<<<<<<<<<<<<<<<<< The console shows a purple warning here. } }
3
0
12k
Dec ’22
Switching Locale with Picker
I'm trying to change the locale of an app with Picker as follows. import SwiftUI @main struct LocaleSwitchCrazyMamaApp: App { var body: some Scene { WindowGroup { let lanSetting = LanguageSetting() ContentView() .environmentObject(lanSetting) .environment(\.locale, lanSetting.locale) } } } class LanguageSetting: ObservableObject { @Published var locale = Locale(identifier: "en") } import SwiftUI struct ContentView: View { @State private var segmentSelection = 0 @EnvironmentObject var languageSetting: LanguageSetting var body: some View { VStack { Text(NSLocalizedString("Hello", comment: "")) .padding(.vertical, 20) Picker("Language", selection: $segmentSelection) { Text("English").tag(0) Text("Japanese").tag(1) Text("French").tag(2) } .frame(width: 200) .pickerStyle(.segmented) .onChange(of: segmentSelection) {newValue in if newValue == 0 { languageSetting.locale = Locale(identifier: "en") } else if newValue == 1 { languageSetting.locale = Locale(identifier: "ja") } else { languageSetting.locale = Locale(identifier: "fr") } } } .padding() } } In addition, I have three locale versions like the following "Hello" = "Hello"; // en.lproj "Hello" = "Bonjour"; //fr.lproj "Hello" = "こんにちは"; // ja.lproj As long as I run the app on a simulator, the language of the Hello text won't change when tap any of the segments. What am I doing wrong? Muchos thankos
3
0
1k
Oct ’23
SwiftUI #Preview with Callback Closure
I have created a simple calendar framework of my own. The screenshot below shows what it looks like. The following lines show a concise version of my calendar framework. The deal is such that the app will return a date when I tap a date button with the callBack closure. import SwiftUI struct ContentView: View { @State private var navigateToAddDate = false @State private var days: [Day] = [] @State var callBack: ((Date) -> Void) private let cols = [ GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()) ] var body: some View { NavigationStack { VStack { LazyVGrid(columns: cols) { ForEach(days, id: \.self) { day in Button(action: { selectedDay = day navigateToAddDate.toggle() }, label: { Image(systemName: "\(day.num).circle.fill") .resizable() .aspectRatio(contentMode: .fit) .foregroundColor(day.show ? dateTextForecolor(day: day) : .clear) }) .disabled(day.isInvalid) } } } } } } struct ContentView_Previews: PreviewProvider { static var callBack: (Date) -> Void = { _ in } static var previews: some View { ContentView(callBack: callBack) } } struct Day: Hashable { let date: Date let text: String let num: Int let dayOfWeek: Int let show: Bool let isInvalid: Bool } Well, PreviewProvider works. Now, I want to use #Preview that comes with iPhone 15. #Preview { var callBack: (Date) -> Void = { _ in } ContentView(callBack: callBack) } And I get a warning and an error. The warning is the following Result of 'ContentView' initializer is unused , which seems to stem from the said warning. How can I make the Preview guy work? Thanks.
3
0
1.7k
Nov ’23