Skip to content

Instantly share code, notes, and snippets.

@agelessman
Created June 23, 2020 11:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agelessman/ed514f2d6dc3378375faf0e64006048e to your computer and use it in GitHub Desktop.
Save agelessman/ed514f2d6dc3378375faf0e64006048e to your computer and use it in GitHub Desktop.
//
// ContentView.swift
// SafelyUpdatingViewStateDemo
//
// Created by 马超 on 2020/6/22.
// Copyright © 2020 马超. All rights reserved.
//
import SwiftUI
struct ContentView: View {
var body: some View {
Example1()
}
}
class MyObservable: ObservableObject {
@Published var name = "你是章三"
}
struct Example4: View {
@EnvironmentObject var obj: MyObservable
var body: some View {
Text("\(obj.name)")
}
}
struct Example3: View {
@State private var width: CGFloat = 0.0
var body: some View {
Text("Width = \(self.width)")
.font(.custom("Cochin", size: 30))
.background(WidthGetter(width: self.$width))
}
struct WidthGetter: View {
@Binding var width: CGFloat
var body: some View {
GeometryReader { proxy -> AnyView in
DispatchQueue.main.async {
self.width = proxy.frame(in: .local).width
print(self.width)
}
return AnyView(Color.clear)
}
}
}
}
struct Example2: View {
@State private var show = false
@State private var direction = ""
var body: some View {
print("更新body direction = \(self.direction) ")
return VStack {
CPUWheel()
.frame(height: 150)
Text("\(self.direction)")
.font(.largeTitle)
Image(systemName: "location.north.fill")
.resizable()
.frame(width: 100, height: 100)
.foregroundColor(.green)
.modifier(RotateEffect(direction: self.$direction, angle: self.show ? 360 : 0))
Button("开始") {
withAnimation(.easeInOut(duration: 3.0)) {
self.show.toggle()
}
}
.padding(.top, 50)
}
}
}
struct RotateEffect: GeometryEffect {
@Binding var direction: String
var angle: Double
var animatableData: Double {
get {
angle
}
set {
angle = newValue
}
}
func effectValue(size: CGSize) -> ProjectionTransform {
DispatchQueue.main.async {
self.direction = self.getDirection(self.angle)
print("更新effectValue direction = \(self.direction) ")
}
let rotation = CGAffineTransform(rotationAngle: CGFloat(angle * (Double.pi / 180.0)))
let offset1 = CGAffineTransform(translationX: size.width / 2.0, y: size.height / 2.0)
let offset2 = CGAffineTransform(translationX: -size.width / 2.0, y: -size.height / 2.0)
return ProjectionTransform(offset2.concatenating(rotation).concatenating(offset1))
}
func getDirection(_ angle: Double) -> String {
switch angle {
case 0..<45:
return "北"
case 45..<135:
return "东"
case 135..<225:
return "南"
case 225..<315:
return "西"
default:
return "北"
}
}
}
struct Example1: View {
@State private var show = false
var body: some View {
VStack {
CPUWheel()
.frame(height: 150)
if show {
OutOfControlView()
}
Button(self.show ? "隐藏" : "显示") {
self.show.toggle()
}
}
}
}
struct OutOfControlView: View {
@State private var count: Int = 0
var body: some View {
DispatchQueue.main.async {
self.count += 1
}
return Text("计算次数:\(self.count)")
.multilineTextAlignment(.center)
}
}
struct CPUWheel: View {
@State private var cpu: Int = 0
var timer = Timer.publish(every: 0.1, on: .current, in: .common).autoconnect()
var body: some View {
let gradient = AngularGradient(gradient: Gradient(colors: [.orange, .green, .blue]), center: .center, angle: .degrees(0))
return Circle()
.stroke(lineWidth: 3)
.foregroundColor(.primary)
.background(Circle().fill(gradient).clipShape(CPUClip(pct: Double(self.cpu))))
.shadow(radius: 4)
.overlay(CPULabel(pct: self.cpu))
.onReceive(timer) { _ in
withAnimation {
self.cpu = Int(Self.cpuUsage())
}
}
}
struct CPUClip: Shape {
let pct: Double
func path(in rect: CGRect) -> Path {
var path = Path()
let cp = CGPoint(x: rect.midX, y: rect.midY)
path.move(to: cp)
path.addArc(center: cp, radius: rect.height / 2, startAngle: .degrees(0), endAngle: .degrees(pct / 100.0 * 360.0), clockwise: false)
path.closeSubpath()
return path
}
}
struct CPULabel: View {
let pct: Int
var body: some View {
VStack {
Text("\(self.pct) %")
.font(.largeTitle)
Text("CPU")
.font(.body)
}
.transaction { $0.animation = nil }
}
}
// Source for cpuUsage(): based on https://stackoverflow.com/a/44134397/7786555
static func cpuUsage() -> Double {
var kr: kern_return_t
var task_info_count: mach_msg_type_number_t
task_info_count = mach_msg_type_number_t(TASK_INFO_MAX)
var tinfo = [integer_t](repeating: 0, count: Int(task_info_count))
kr = task_info(mach_task_self_, task_flavor_t(TASK_BASIC_INFO), &tinfo, &task_info_count)
if kr != KERN_SUCCESS {
return -1
}
return [thread_act_t]().withUnsafeBufferPointer { bufferPointer in
var thread_list: thread_act_array_t? = UnsafeMutablePointer(mutating: bufferPointer.baseAddress)
var thread_count: mach_msg_type_number_t = 0
defer {
if let thread_list = thread_list {
vm_deallocate(mach_task_self_, vm_address_t(bitPattern: thread_list), vm_size_t(Int(thread_count) * MemoryLayout<thread_t>.stride))
}
}
kr = task_threads(mach_task_self_, &thread_list, &thread_count)
if kr != KERN_SUCCESS {
return -1
}
var tot_cpu: Double = 0
if let thread_list = thread_list {
for j in 0..<Int(thread_count) {
var thread_info_count = mach_msg_type_number_t(THREAD_INFO_MAX)
var thinfo = [integer_t](repeating: 0, count: Int(thread_info_count))
kr = thread_info(thread_list[j], thread_flavor_t(THREAD_BASIC_INFO),
&thinfo, &thread_info_count)
if kr != KERN_SUCCESS {
return -1
}
let threadBasicInfo = convertThreadInfoToThreadBasicInfo(thinfo)
if threadBasicInfo.flags != TH_FLAGS_IDLE {
tot_cpu += (Double(threadBasicInfo.cpu_usage) / Double(TH_USAGE_SCALE)) * 100.0
}
} // for each thread
}
return tot_cpu
}
}
static func convertThreadInfoToThreadBasicInfo(_ threadInfo: [integer_t]) -> thread_basic_info {
var result = thread_basic_info()
result.user_time = time_value_t(seconds: threadInfo[0], microseconds: threadInfo[1])
result.system_time = time_value_t(seconds: threadInfo[2], microseconds: threadInfo[3])
result.cpu_usage = threadInfo[4]
result.policy = threadInfo[5]
result.run_state = threadInfo[6]
result.flags = threadInfo[7]
result.suspend_count = threadInfo[8]
result.sleep_time = threadInfo[9]
return result
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment