初めに
冬,寒いですよね.
あなたの手の中にある、スマートなフォン.略してスマホ.
スマートフォンはスマートなフォンなので, ホッカイロにだってなれるはずです.
作っていきましょう.
使い方
アプリを起動します.
あったかくなるのを待ちましょう.
あったかい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