Skip to content

Instantly share code, notes, and snippets.

@katsuyoshi
Last active March 17, 2023 07:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save katsuyoshi/48032367905970a2ae6c02a36c4f5e4b to your computer and use it in GitHub Desktop.
Save katsuyoshi/48032367905970a2ae6c02a36c4f5e4b to your computer and use it in GitHub Desktop.
iOSのBackgrounTaskでデッドロック
import SwiftUI
struct ContentView: View {
@Environment(\.scenePhase) var scenePhase
@State var controller = Controller()
@ObservedObject var publisher = Publisher()
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
HStack {
Spacer()
Text("count")
Text(String(describing: publisher.count))
Spacer()
}
Button {
if publisher.run {
publisher.stop()
} else {
publisher.start()
}
} label: {
Text(publisher.run ? "Stop" : "Start")
}
.disabled(!publisher.run && !publisher.stopped)
}
.padding()
.onAppear() {
controller.publisher = publisher
}
.onChange(of: scenePhase) { newPhase in
if newPhase == .active {
print("Active")
controller.becomeForground()
} else if newPhase == .inactive {
print("Inactive")
} else if newPhase == .background {
print("Background")
controller.becomeBackground()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
import Foundation
import UIKit
class Controller
{
private var taskIdentifier: UIBackgroundTaskIdentifier!
var publisher: Publisher?
func becomeBackground() {
publisher!.stop()
taskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: {
UIApplication.shared.endBackgroundTask(self.taskIdentifier)
})
while publisher!.stopped == false {
Thread.sleep(forTimeInterval: 1)
}
UIApplication.shared.endBackgroundTask(taskIdentifier)
}
func becomeForground() {
publisher!.start()
}
}
import Foundation
class Publisher: ObservableObject {
@Published var run = false
@Published var stopped = true
@Published var count: UInt32 = 0
private var thread: Thread!
init() {
thread = Thread(block: {
DispatchQueue.main.async {
self.stopped = !self.run
}
while(true) {
while self.run {
Thread.sleep(forTimeInterval: 1)
DispatchQueue.main.async {
self.count += 1
}
}
DispatchQueue.main.async {
self.stopped = true
}
while !self.run {
Thread.sleep(forTimeInterval: 1)
}
DispatchQueue.main.async {
self.stopped = false
}
}
})
thread.start()
}
func start() {
run = true
}
func stop() {
run = false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment