1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クソアプリAdvent Calendar 2024

Day 22

体の芯からあったまるアプリケーション

Last updated at Posted at 2024-12-21

初めに

冬,寒いですよね.

あなたの手の中にある、スマートなフォン.略してスマホ.
スマートフォンはスマートなフォンなので, ホッカイロにだってなれるはずです.
作っていきましょう.


使い方

アプリを起動します.

あったかくなるのを待ちましょう.

あったかいiOSアプリ

材料を紹介します.

材料 個数
XCode 1個
ペラペラのView 1個
std::thread 論理コアに応じた数
いい感じの処理 (意味のない処理だったかまわない) 少々

処理をおこなうクラス

今回の目的はコア分いっぱいに処理を実行して体を温めることですので,GCDなど使う必要はありません.むしろ使いたくありません.そのため,C++のstd::threadで必要な数分スレッドを作ることにしました.

ただしいままでは, SwiftからC++のクラスを呼び出すにはObj-Cでラップするなど少々めんどくさい実装が必要でした.素晴らしいことに,最近SwiftからC++が呼べるようになったので,これを用いていきます.

namespace Warmer{
class Core{
private:
    std::vector<Process*> pi_;
    
    int thread_n_ = 1;
    int current_thread_ = 0;

public:
    Core(){
        thread_n_ = std::thread::hardware_concurrency();
    }
    
    ~Core(){}
            
    void start(){
        for(int i=0; i<thread_n_; i++){
            Process* calc = new Process();
            calc->run();
            pi_.push_back(calc);
        }
    }

    // ~~~~ 中略 ~~~~~
    
    void stop(){
        for(auto e : pi_){
            e->stop();
        }
        
        for(auto e : pi_){
            delete e;
        }
        
        pi_.clear();
    }      
};
};

std::threadを持つクラスないで,無限にこの___taskを呼びまくります.
少々の処理といいましたか,これでもかってくらいのゴリゴリの処理を入れましょう.

とにかく和積の数を稼ぎます.pow関数なんかもいいですね.
コンパイラに不要と思われないように出力した値はちゃんと使いうます.

ちなみに,意味のない処理だとCPUがかわいそうなのでモンテカルロ法で円周率を求めています.

void Warmer::Process::__task(uint64_t cycle, double x, double y){
    std::lock_guard<std::mutex> lock(mtx_);
    
    if(cycle == 0){
        pi_count_ = 0;
        return;
    }
    
    if (x*x + y*y <= 1.0) {
        pi_count_++;
    }

    double pi = ((double)pi_count_ / (double) cycle) * 4.0;
    pi_.store(pi, std::memory_order_release);
    
    
    // なんかよくわかんないけど和積を増やそう
    double sa = 0.0;
    double ca = 0.0;
    
    int N = N_;
    int M = M_;
    
    M_ = std::max(0, M_);
    M_ = std::min(M_, MAX_M);
    
    N_ = std::max(0, N_);
    N_ = std::min(N_, MAX_N);
    
    for(uint64_t i=0; i<N; i++){
        double cy = (double) N;
        
        double s = 0;
        double c = 0;
        
        for(int j=0; j<M; j++){
            s += std::sin((double) N / 1000.0 * std::pow(2.0, j) * 1.0 * pi) * ((double)i / cy) / (double) M;
            c += std::cos((double) N / 1000.0 * std::pow(2.0, j) * 1.0 * pi) * ((double)i / cy) / (double) M;
        }                                    
                
        sa += s / cy;
        ca += c / cy;
    }
            
    dummy_ += sa + ca;
    
    if(cycle % 1000000 == 0){
        printf("%f\n", dummy_);
    }
}

ペラペラのView

適当なのはご了承ください.

class ContentModel: ObservableObject{
    enum State{
        case normal
        case fair
        case serious
        case critical
        
        var color: Color{
            switch self{
                case .normal:
                    return .blue
                case .fair:
                    return .green
                case .serious:
                    return .yellow
                case .critical:
                    return .red
            }
        }
        
        var label: String{
            switch self{
                case .normal:
                    return "冷たいね"
                case .fair:
                    return "ちょっとあったかい"
                case .serious:
                    return "あったかい〜"
                case .critical:
                    return "あちち"
            }
        }
        
        init(_ state: ProcessInfo.ThermalState){
            switch state {
                case .nominal:
                    self = .normal
                case .fair:
                    self = .fair
                case .serious:
                    self = .serious
                case .critical:
                    self = .critical
                @unknown default:
                    self = .normal
            }
        }
    }
    
    
    
    @Published var scale: Double = 1.0
    @Published var boost: Double = 0.0
    @Published var level: Double = 0.0
    @Published var thermalState: State = .normal
    
    var core: Warmer.Core
    
    init(){
        self.core = Warmer.Core()
        self.core.start();
        var timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { _ in
            self.scale = self.core.pi() / 3.14159265358979
            self.thermalState = .init(ProcessInfo.processInfo.thermalState)
        })
    }
    
    func updateBoost(_ value: Double) {
        core.boost(value)
        objectWillChange.send()
    }
    
    func updateLevel(_ value: Double) {
        core.level(value)
        objectWillChange.send()
    }
}
struct ContentView: View {
    
    @ObservedObject var viewModel: ContentModel
    
    init(){
      viewModel = ContentModel()
    }
        
    var body: some View {
        VStack{
            Spacer()
            HStack{
                Spacer()
                ZStack{
                    Circle()
                        .foregroundStyle(viewModel.thermalState.color)
                        .frame(width: 300, height: 300)
                    Circle()
                        .stroke(Color.blue, lineWidth: 3)
                        .frame(width: 300, height: 300)
                        .scaleEffect(viewModel.scale)
                    Text(viewModel.thermalState.label)
                        .foregroundStyle(Color.white)
                        .font(.system(size: 18, weight: .bold))
                    
                }
                Spacer()
            }
            Spacer()
            
            HStack{
                Text("Boost")
                Slider(value: $viewModel.boost, in: 0...1, step: 0.1){ newValue in
                    viewModel.updateBoost(viewModel.boost)
                }
            }
            
            HStack{
                Text("Level")
                Slider(value: $viewModel.level, in: 0...1, step: 0.1){_ in
                    viewModel.updateLevel(viewModel.level)
                }
            }
        }
        .padding()
    }
}

XCodeで10秒焼き上げます

あなたのXCodeに入れて、10秒ほど焼き(コンパイルし)ます.

完成!

あとは,立ち上げてまつだけ!

けっこう暖かくなります.
温度計がないので,詳細な温度はわかりませんが ;-(

最後に

これで寒い冬も乗り切れます.

バッテリーが1分で1%減りますが...
(iPhone SE 3rd)

免責事項

バッテリーの劣化を引き起こすため,試さないでください.
試してしまって記事の内容について生じるいかなる損害についても,私は責任を負いかねます....![Simulator

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?