4

NSTimer を作成し、それをバックグラウンド スレッドの実行ループに追加しています。私のコードは、この回答のバックグラウンド スレッドの例のようなものです: iPhone-SDK:Call a function in the background?

タイマーを作成し、gdb I から runloop にアタッチすると、次のpo runLoopように出力されます。

<CFRunLoop 0x695b090 [0x16a62c0]>{wakeup port = 0x6907, stopped = false,
current mode = kCFRunLoopDefaultMode,
common modes = <CFBasicHash 0x6936e60 [0x16a62c0]>{type = mutable set, count = 1,
entries =>
    1 : <CFString 0x16abba8 [0x16a62c0]>{contents = "kCFRunLoopDefaultMode"}
}
,
common mode items = <CFBasicHash 0x695e160 [0x16a62c0]>{type = mutable set, count = 1,
entries =>
    0 : <CFRunLoopTimer 0x69398a0 [0x16a62c0]>{valid = Yes, interval = 6, next fire date = 329774303, callout = __NSFireTimer (0x212399), context = <CFRunLoopTimer context 0x6903a10>}
}
,
modes = <CFBasicHash 0x6904120 [0x16a62c0]>{type = mutable set, count = 1,
entries =>
    1 : <CFRunLoopMode 0x6946180 [0x16a62c0]>{name = kCFRunLoopDefaultMode, port set = 0x6807, timer port = 0x6b03, 
    sources0 = (null),
    sources1 = (null),
    observers = (null),
    timers = <CFArray 0x695e180 [0x16a62c0]>{type = mutable-small, count = 1, values = (
    0 : <CFRunLoopTimer 0x69398a0 [0x16a62c0]>{valid = Yes, interval = 6, next fire date = 329774303, callout = __NSFireTimer (0x212399), context = <CFRunLoopTimer context 0x6903a10>}
)}
},

}
}

これは、1 つのタイマーが runloop にアタッチされていることを示しています。後でタイマーを無効にした後、NSRunloop 実行メソッドは終了しませんが、デバッガーを一時停止して gdb からpo runLoop再び次のように表示されます。

<CFRunLoop 0x695b090 [0x16a62c0]>{wakeup port = 0x6907, stopped = false,
current mode = kCFRunLoopDefaultMode,
common modes = <CFBasicHash 0x6936e60 [0x16a62c0]>{type = mutable set, count = 1,
entries =>
    1 : <CFString 0x16abba8 [0x16a62c0]>{contents = "kCFRunLoopDefaultMode"}
}
,
common mode items = <CFBasicHash 0x695e160 [0x16a62c0]>{type = mutable set, count = 0,
entries =>
}
,
modes = <CFBasicHash 0x6904120 [0x16a62c0]>{type = mutable set, count = 1,
entries =>
    1 : <CFRunLoopMode 0x6946180 [0x16a62c0]>{name = kCFRunLoopDefaultMode, port set = 0x6807, timer port = 0x6b03, 
    sources0 = (null),
    sources1 = (null),
    observers = (null),
    timers = <CFArray 0x695e180 [0x16a62c0]>{type = mutable-small, count = 0, values = ()}
},

}
}

これで、"timers" エントリのオブジェクトは 0 になりました。しかし、スレッドは実行され続けます。画面を離れて戻ってくることがよくあるため、バックグラウンド スレッドが蓄積され、リソースが多すぎると最終的にアプリが強制終了されます。無効化された後、タイマーは起動しませんが、バックグラウンド スレッドは残ります。

タイマーをメイン スレッドに戻すか、NSThread sleepForTimeInterval を使用して独自の単純なタイマー スレッドを作成できることはわかっていますが、GUI の更新用にメイン スレッドを維持し、可能であれば NSTimer を使用したいと考えています。

4

3 に答える 3

2

これにより、実行ループがうまく停止します。

[[NSRunLoop currentRunLoop] runUntilDate: [NSDate date]];

ただし、メイン スレッドで実行される可能性がある (したがってメインの実行ループを使用する) コードを記述している場合は、これを行う前に、現在の実行ループがメインの実行ループであるかどうかを確認する必要があります。そうしないと、アプリが爆撃されます。

// Kill the runloop now.
NSRunLoop* rl = [NSRunLoop currentRunLoop]; // Get the runloop
if (rl != [NSRunLoop mainRunLoop])
{
    // Set it running again, but only until now. 
    // In other words, STOP!!!
    [rl runUntilDate: [NSDate date]];
}
于 2012-05-25T04:38:43.800 に答える
1

-[NSRunLoop run]ドキュメントから:

既知のすべての入力ソースとタイマーを実行ループから手動で削除しても、実行ループが終了する保証はありません。

おそらくループ内で別のメソッドを使用runMode:beforeDate:し、同時にタイマーを無効にして、実行ループを終了する必要があることを示すフラグを設定する必要があります。

于 2011-06-14T20:53:51.450 に答える
0

[NSTimer invalidate] のドキュメントを読む必要がありました.... このメソッドは、タイマーがインストールされている同じスレッドから呼び出す必要があります。同じスレッドから呼び出さないと、タイマー スレッドは終了しません。

于 2011-06-14T22:02:47.003 に答える