var ref = Database.database().reference().child("Essages")
var childRef = Database.database().reference().child("Essages").childByAutoId()
#IBAction func sendBtn(_ sender: Any) {
posting()
}
func posting(){
let values = ["message" : captionTextView.text] as [String : Any]
childRef.updateChildValues(values) { (error, ref) in
if error != nil {
print("error")
}else {
let = Timer.scheduledTimer(timeInterval: 90000, target: self, selector: #selector(self.onTick), userInfo: nil, repeats: false)
}
}
}
func onTick(){
childRef.removeValue()
}
If the app is open then the timer is working and it is deleting the data. But if I close the app the timer is not working and the data is not deleted. Please help me in sorting this problem. I'm trying to get feature like snapchat (deleting in 24hrs).
You could try perhaps a new Firebase cloud function feature, which is I think the best and easiest option. It was in beta until couple of weeks ago but now it's fully functional.
There was a similar question on another thread here. You can also find a nice tutorial on the Firebase Blog. In general, following some good coding practices, you shouldn't be triggering this from a client. Data cleanup, and in any other form of updates should be done by the backend itself.
Related
I'm somewhat new to this and this is my first question on stackoverflow. Thanks in advance for your help and bear with me if my formatting sucks
I've got multiple views within my app (all displaying data using tableview subviews) that need to update automatically when the data changes on the database (Firestore), i.e. another user updates the data.
I've found a way to do this which is working well, but I want to ask the community if there's a better way.
Currently, I am creating a Timer object with a timeInterval of 2. On the interval, the timer queries the database and checks a stored data sample against updated data. If the two values vary, I run viewDidLoad which contains my original query, tableView.reloadData(), etc..
Any suggestions or affirmations would be very useful.
var timer = Timer()
var oldChallengesArray = [String]()
var newChallengesArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
//set tableview delegate
mainTableView.delegate = self
mainTableView.dataSource = self
//set challengesmodel delegate
challengesModel.delegate = self
//get challenges
DispatchQueue.main.async {
self.challengesModel.getChallenges(accepted: true, challengeDenied: false, incomingChallenges: false, matchOver: false)
self.mainTableView.reloadData()
}
scheduledTimerWithTimeInterval()
}
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 1 seconds
timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(self.updateTableView), userInfo: nil, repeats: true)
}
#objc func updateTableView(){
ChallengeService.getAllUserChallengeIDs(accepted: true, challengeDenied: false, matchOver: false) { (array) in
if array.isEmpty {
return
} else {
self.newChallengesArray = array
if self.oldChallengesArray != self.newChallengesArray {
self.oldChallengesArray = self.newChallengesArray
self.newChallengesArray.removeAll()
self.viewDidLoad()
}
}
}
}
Firestore is a "realtime database", that means that the database warns you when changes happen to the data. To achieve that the app needs to subscribe to relevant changes in the db. The sample code below can be found here:
db.collection("cities").document("SF")
.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("Error fetching document: \(error!)")
return
}
guard let data = document.data() else {
print("Document data was empty.")
return
}
print("Current data: \(data)")
}
Also, I would like to point out that calling viewDidLoad is incorrect, you should never call viewDidLoad yourself, create an func to update the data. Something like this:
DispatchQueue.main.async {
self.mainTableView.reloadData()
}
I am trying to clear the pasteboard after a string is copied after 10s. The requirements are the following:
After 10s, the copied text is cleared and therefore not pasteable in
the current app and other apps as well(ex. iMessage, Safari)
If non-identical text is copied, when the 10s is up the timer will not wipe it out
Attempts
I have tried doing this with only DispatchQueue.main.async however, this was freezing the original app.
I have tried doing it with only DispatchQueue.global(qos: .background).async however, when I switched to another app(iMessage), after 10s I could still paste the number. I had to go back to the original app and back to iMessage for it to be wiped out
This is my latest attempt and its the same behavior as #2, only getting wiped out when I go back to the original app and back to iMessage
private func clearTextAfterDelay(_ copiedCardNumber: String) {
expirationTimer?.invalidate()
expirationTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { timer in
DispatchQueue.main.async {
let currentTextOnClipBoard = UIPasteboard.general.string
if currentTextOnClipBoard == copiedCardNumber {
UIPasteboard.general.setValue("", forPasteboardType: UIPasteboard.Name.general.rawValue)
}
}
}
DispatchQueue.global(qos: .background).async {
let runLoop = RunLoop.current
runLoop.add(self.expirationTimer!, forMode: .default)
runLoop.run()
}
}
Along with this article and the above comment I was able to figure it out https://medium.com/#abhimuralidharan/finite-length-tasks-in-background-ios-swift-60f2db4fa01b. Cheers
class ViewController: MvpViewController {
private var expirationTimerforBackground: Timer?
private var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier.invalid
private func clearTextAfterDelay(_ copiedCardNumber: String) {
backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
self?.endBackgroundTask()
}
assert(backgroundTask != UIBackgroundTaskIdentifier.invalid)
self.expirationTimerforBackground?.invalidate()
self.expirationTimerforBackground = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { [weak self] _ in
let currentTextOnClipBoard = UIPasteboard.general.string
if currentTextOnClipBoard == copiedCardNumber {
UIPasteboard.general.setValue("", forPasteboardType: UIPasteboard.Name.general.rawValue)
}
self?.endBackgroundTask()
}
}
private func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTask)
backgroundTask = UIBackgroundTaskIdentifier.invalid
}
}
Number 2 doesn't work because your app gets suspended almost immediately upon resigning active. So you'd need to extend your app's active time by using background tasks.
Take a look at the beginBackgroundTaskWithExpirationHandler docs.
This method requests additional background execution time for your app. Call this method when leaving a task unfinished might be detrimental to your app’s user experience. For example, call this method before writing data to a file to prevent the system from suspending your app while the operation is in progress.
I am trying to add(move forward) 10 second song duration or minus(move backward) 10 second in Spotify player but i am really confused how to add or minus.
When i m trying to use this code the song is not changed duration
// forward button action
#IBAction func moveFrdBtnAction(_ sender: Any) {
SpotifyManager.shared.audioStreaming(SpotifyManager.shared.player, didSeekToPosition: TimeInterval(10))
}
// spotify delegate method seekToPosition
func audioStreaming(_ audioStreaming: SPTAudioStreamingController!, didSeekToPosition position: TimeInterval) {
player?.seek(to: position, callback: { (error) in
let songDuration = audioStreaming.metadata.currentTrack?.duration as Any as! Double
self.delegate?.getSongTime(timeCount: Int(songDuration)+1)
})
}
We are making a music application using the same SDK in both the platforms (Android & iOS), the seekToPosition method of the Spotify SDK is working correctly in the Android version, however, it is not working in the iOS one.The delegate method calls itself but the music stops.
Can you kindly let us know why this scenario is happening, and what should we do to run it on the iOS devices as well.
Can someone please explain to me how to solve this , i've tried to solve this but no results yet.
Any help would be greatly appreciated.
Thanks in advance.
I don't use this API so my answer will be based your code and Spotify's reference documentation.
I think there are a few things wrong with your flow:
As Robert Dresler commented, you should (approximately) never call a delegate directly, a delegate calls you.
I'm pretty sure your action currently results in jumping to exactly 10 seconds, not by 10 seconds.
(As an aside, I'd suggest changing the name of your function moveFrdBtnAction to at least add more vowels)
Anyway, here's my best guess at what you want:
// forward button action
#IBAction func moveForwardButtonAction(_ sender: Any) {
skipAudio(by: 10)
}
#IBAction func moveBackButtonAction(_ sender: Any) {
skipAudio(by: -10)
}
func skipAudio(by interval: TimeInterval) {
if let player = player {
let position = player.playbackState.position // The documentation alludes to milliseconds but examples don't.
player.seek(to: position + interval, callback: { (error) in
// Handle the error (if any)
})
}
}
// spotify delegate method seekToPosition
func audioStreaming(_ audioStreaming: SPTAudioStreamingController!, didSeekToPosition position: TimeInterval) {
// Update your UI
}
Note that I have not handled seeking before the start of the track, nor after the end which could happen with a simple position + interval. The API may handle this for you, or not.
You could take a look at the examples here: spotify/ios-sdk. In the NowPlayingView example they use the 'seekForward15Seconds', maybe you could use that? If you still need 10s I have added a function below. The position is in milliseconds.
"position: The position to seek to in milliseconds"
docs
ViewController.swift
var appRemote: SPTAppRemote {
get {
return AppDelegate.sharedInstance.appRemote
}
}
fileprivate func seekForward15Seconds() {
appRemote.playerAPI?.seekForward15Seconds(defaultCallback)
}
fileprivate seekBackward15Seconds() {
appRemote.playerAPI?.seekBackward15Seconds(defaultCallback)
}
// TODO: Or you could try this function
func seekForward(seconds: Int){
appRemote.playerAPI?.getPlayerState({ (result, error) in
// playback position in milliseconds
let current_position = self.playerState?.playbackPosition
let seconds_in_milliseconds = seconds * 1000
self.appRemote.playerAPI?.seek(toPosition: current_position + seconds_in_milliseconds, callback: { (result, error) in
guard error == nil else {
print(error)
return
}
})
})
}
var defaultCallback: SPTAppRemoteCallback {
get {
return {[weak self] _, error in
if let error = error {
self?.displayError(error as NSError)
}
}
}
}
AppDelegate.swift
lazy var appRemote: SPTAppRemote = {
let configuration = SPTConfiguration(clientID: self.clientIdentifier, redirectURL: self.redirectUri)
let appRemote = SPTAppRemote(configuration: configuration, logLevel: .debug)
appRemote.connectionParameters.accessToken = self.accessToken
appRemote.delegate = self
return appRemote
}()
class var sharedInstance: AppDelegate {
get {
return UIApplication.shared.delegate as! AppDelegate
}
}
Edit1:
For this to work you need to follow the Prepare Your Environment:
Add the SpotifyiOS.framework to your Xcode project
Hope it helps!
I have a project in which I need to update the user's current location coordinates on the API server. How can I achieve this? Is continuously calling the API a good idea (I think no)?
I need to update coordinates continuously so other users can see me like in the Uber app the very first time we can see drivers near me.
Maybe you can implement a timer, and make a POST request by sending your lat long periodically.
class ViewController: UIViewController {
var timer: Timer!
override func viewDidLoad() {
timer = Timer.scheduledTimer(timeInterval: 10.0, target: self, selector: #selector(makeRequest), userInfo: nil, repeats: true)
}
#objc func makeRequest() {
// make your post request here.
}
}
For example the timer given above will call makeRequest method every 10 seconds.
If you don't know much about networking, make a research on the following topics:
Swift Networking Layer, Alamofire, URLSession
**Step 1 :- Get latitude and long. of the user first.**
Reference URL:- https://stackoverflow.com/questions/12736086/how-to-get-location-latitude-longitude-value-in-variable-on-ios
**Step 2:- Define following variables globally.**
var timer:Timer?
var sourceLatitude = CLLocationDegrees()
var sourceLongitude = CLLocationDegrees()
**Step 3:- Setup timer for continuous update as below.**
override func viewDidLoad()
{
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 15, target: self, selector: #selector(self.updateDriverLoction), userInfo: nil, repeats: true)
}
**Step 4:- call appropriate method for sending and updating lat. long. to the server using any of networking API.(In my case I have used Alamofire)**
// must be internal or public.
#objc func updateDriverLoction() {
if Reachability.isConnectedToNetwork() {
let param1:[String:String] = [
"latitude" : "\(sourceLatitude)",
"longitude" : "\(sourceLongitude)"
]
ServerClass.sharedInstance.putRequestWithUrlParameters(param1, path: BASE_CAB_URL + PROJECT_URL.UPDATE_DRIVER_LOCATION_API, successBlock: { (json) in
print(json)
let success = json["success"].stringValue
if success == "true" {
}
else {
}
}, errorBlock: { (NSError) in
// UIAlertController.showInfoAlertWithTitle("Alert", message: kUnexpectedErrorAlertString, buttonTitle: "Okay")
})
}
}
else{
UIAlertController.showInfoAlertWithTitle("Alert", message: "Please Check internet connection", buttonTitle: "Okay")
}
}
As a swift beginner, I'm building a simple app which will get data from a website to update the label text.
In the ViewController.swift I begin with a function called requestCycle():
override func viewDidLoad() {
super.viewDidLoad()
requestCycle()
}
In this requestCycle() function I create a timer to call the http request function basicAuthHttpRequest():
func requestCycle(){
self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(ViewController.basicAuthHttpRequest), userInfo: nil, repeats: true);
RunLoop.current.add(self.timer, forMode: RunLoopMode.commonModes);
}
In the basicAuthHttpRequest() function, I set up an http request to get data from a url, and use the data to update the label text:
...
//http request, parse json, store the data in TempIn
let TempInString = String(describing: TempIn!)
self.TempInLabel.text = TempInString
print(TempInString)
print(self.TempInLabel.text!)
...
When I run the app, the data will be printed("33" and Optional("33")) and NO ERRORs occur. However, the text of the label shown is not changed at all.
If I use a button to trigger the function basicAuthHttpRequest(), after clicking the button, the label text will be changed in a few seconds.
What's wrong with my poor timer? =.=
You have to update text on the main thread.
DispatchQueue.main.async {
let TempInString:String = String(describing: TempIn!)
self.TempInLabel.text = TempInString as String
}
Try below code :-
DispatchQueue.main.async(execute: { self.TempInLabel.text = TempInString as String })
The timer is running on background thread. so you have to update label value with main thread. You have to use below code for the same.
self.performSelector(onMainThread: #selector(updateUI), with: nil, waitUntilDone: true)
func updateUI() {
print("here update your UI")
}
Also you can do with OperationQueue.
OperationQueue.main.addOperation({
print("here update your UI")
})