I have just got my app approved and it is life in App Store. This is a paid app with an auto-renewable subscription. My design model is to allow the users to try it for free before they subscribe. The trial period is managed from the cloud. But when publishing the app in App Store it is right away presented with the purchase button instead of the GET button or Try It for Free button. This is misleading because the users are not ready to purchase the product they have not tried! I contacted the support but I have the impression that I was talking to robots that do not take time to understand the logic. As the consequence, my users are charged right away before being even given a chance to try it; as per the design at the end of a month, they are being presented with a subscription screen to choose from subscribing for a monthly renewable or a yearly! It does not make any sense. Why can't App Store allow us to determine and manage the trial period and keep IAP as a post-trial step? This model is good for new users and for the business
Post
Replies
Boosts
Views
Activity
I have discovered the issue and I would need help to come up with a best completion handler to resolve my problem.
As shown below, my r_feedback() function is exiting before new messages are appended therefore TableView.reloadData() is reloading old data because new data are added after.
My solution should be to force my TableView.reloadData() to be called only once my arrayFeedback.append has completed
r_feedback(rtaskId:) exiting r_feedback
r_feedback(rtaskId:) arrayFeedback.append completed
r_feedback(rtaskId:) reload has completed
2021-03-08 01:54:30.113337-0500 sokyTasks[7745:616019] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
viewDidAppear(_:) going to loadData
loadData() going to buttonChange
buttonChange() button has changed
r_feedback(rtaskId:) queryFeedback
r_feedback(rtaskId:) going to reloadData
loadData() going to buttonChange
buttonChange() button has changed
r_feedback(rtaskId:) queryFeedback
r_feedback(rtaskId:) going to reloadData
buttonChange() was let out because it is included only to keep my codes clean. It does change the status on a button and has got nothing to do with the viewController. I can even leave it out. It is not related. However composeButton() does because the codes call loadata() after inserting a new message and I guess this one is related.
func buttonChange() {
let stat = taskStatus?.text
let rqType = Int(reqTypeIndex.text ?? "") ?? 0
switch(rqType) {
case 0:
if (stat == status[1]) || (stat == status[3]) {
statusChange(imageLabel: task_image[2])
} else {
statusChange(imageLabel: "")
}
case 1:
if (stat == status[2]) {
statusChange(imageLabel: task_image[3])
} else {
statusChange(imageLabel: "")
}
default:
statusChange(imageLabel: "")
}
}
@IBAction func composeButton(_ sender: Any) {
if (feedInputField.text != "" ) {
let reqType = Int(reqTypeIndex.text ?? "") ?? 0
AddFeedbacks(message: feedInputField.text ?? "", taskId: idTask?.text ?? "", atype: reqType)
loadData()
feedInputField.text = ""
}
}
func AddFeedbacks(message: String,taskId: String,atype: Int) {
if currentUser != nil {
let feed = PFObject(className: "Feedback")
feed["TaskId"] = taskId
feed["TaskFeedback"] = message
feed["UserNameFrom"] = currentUser?.username!
feed["AType"] = atype
feed.saveInBackground()
}
}
PFObject() is a framework class
feedInputField and composeButton are on the toolbar.
Thanks for your help
I have noticed that when installed on the iPhone, the code works without error message.
Can someone show me how to close this case? Sorry I am new to Xcode and I have just developed my first app with XCode therefore I am new to this forum
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
loadData()
}
func loadData() {
r_feedback(rtaskId: idTask.text ?? "")
buttonChange()
}
func r_feedback(rtaskId: String) {
var singleFeed = myFeedback()
self.arrayOfFeedback.removeAll()
queryFeedback(taskId: rtaskId).findObjectsInBackground { (objects, error) in
if let objects = objects {
if (objects.count 0) {
for eachFeed in objects {
singleFeed.feedDate = eachFeed.createdAt!
singleFeed.userNameFrom = eachFeed["UserNameFrom"] as? String
singleFeed.feedMessage = eachFeed["TaskFeedback"] as? String
singleFeed.atype = eachFeed["AType"] as? Int
self.arrayOfFeedback.append(singleFeed)
}
} else {
singleFeed.feedDate = nil
singleFeed.userNameFrom = ""
singleFeed.feedMessage = ""
singleFeed.atype = nil
}
DispatchQueue.main.async {
self.fTableView.reloadData()
}
}
}
}
func queryTasks(field: String) - PFQueryPFObject {
let query = PFQuery(className:"Tasks")
query.whereKey(field, equalTo: (currentUser?.username)!)
query.order(byAscending: "TaskDeadline")
return query
}
I have posted the complete code. This code reloads the viewcontroller without issue if I place the update textfield on another viewcontroller that is called on top of the one displaying the feedback because the Back button will call viewDidAppear() function. But I prefer having update textfield on the same viewcontroller the way the chat message works.
Your help is appreciated.
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
let emailNumberCount = contact.emailAddresses.count
guard emailNumberCount 0 else {
actionOwnerEmail.text = ""
dismiss(animated: true, completion: nil)
let alert = UIAlertController(title: "No email found", message: "Please add email to your addressbook", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true)
return
}
let email = contact.emailAddresses[0].value as String
actionOwnerEmail.text = email
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
dismiss(animated: true, completion: nil)
}
I am using the above codes but when calling CNContactPicker, I have the error message.
I need your help community; my app is complete but I am busy making sure that I have it clean
Unfortunately, there is no code. It is just the Back Button that is part of Nav Controller however the ViewController in question
called by the following codes:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? CommentsViewController {
vc.idTaskAction = cellTaskId
vc.requestType = segm
vc.taskText = taskTxt
vc.t_status = curStatus
vc.userName = currentUser?.email ?? ""
}
}
CommentsViewController is wrapped into navigation controller and its Back Button is issuing the above error message randomly
No, I am still having the same issue.
It happens only when I load the application. The first time I post a message to be added, reloadData() is delayed until a second message is posted. From there once the app is in memory, it works normally.
func queryFeedback(taskId: String) - PFQueryPFObject {
let query = PFQuery(className:"Feedback")
query.whereKey("TaskId", equalTo: taskId)
query.order(byAscending: "CreatedAt")
return query
}
queryFeedback() is my function just to simplify my code by returning a PFOBject that is a snapshot of my query.
This PFOBject is then carried in background into my r_feedback() function.
Thanks for your help, my format works now
saveInBackground() is a Parse Server function that saves data to mongoDB.
However I have tried to include self.fTableView.reloadData() of my r_feedback() function into DispatchQueue.main.async and it seems to work but I am still testing:
DispatchQueue.main.async {
self.fTableView.reloadData()
}
func addFeedbacks(message: String,taskId: String,atype: Int) {
if currentUser != nil {
let feed = PFObject(className: "Feedback")
feed["TaskId"] = taskId
feed["TaskFeedback"] = message
feed["UserNameFrom"] = currentUser?.username!
feed["AType"] = atype
feed.saveInBackground()
}
}
I am sorry I am new to the forum and I am still struggling to format my text.
I think Claude31 is right but I need help to make it work. "feed.saveInBackgound()" does the job after because I have made a test by inserting print(arrayFeedback) between "addFeedbacks" and "loadData()" and the result is that there is a delay which means reloadData() is called before "arrayFeedback" is updated.
The following is the function that loadData()
//**********************************
func r_feedback(rtaskId: String) {
var singleFeed = myFeedback()
self.arrayOfFeedback.removeAll()
queryFeedback(taskId: rtaskId).findObjectsInBackground { (objects, error) in
if let objects = objects {
if (objects.count 0) {
for eachFeed in objects {
singleFeed.feedDate = eachFeed.createdAt!
singleFeed.userNameFrom = eachFeed["UserNameFrom"] as? String
singleFeed.feedMessage = eachFeed["TaskFeedback"] as? String
singleFeed.atype = eachFeed["AType"] as? Int
self.arrayOfFeedback.append(singleFeed)
}
} else {
singleFeed.feedDate = nil
singleFeed.userNameFrom = ""
singleFeed.feedMessage = ""
singleFeed.atype = nil
}
self.fTableView.reloadData()
}
}
}
//**********************************
In turn funcion r_feedback(rtaskId: String) calls function queryFeedback() that fetches data in background and appends my array arrayOfFeedback and at the end calls TableView.reloadData(). I am using Parse Server as backend.
I just want to clarifies that if I use an additional viewController with textField to add messages, because this other viewController is called on top of the viewController that displays all the messages, it works but because I do not prefer to go have additional viewController but instead use the same viewController to update the messages, that's when I have this behavior