我有一个NSRunLoop对象,我附加了定时器和流.它很棒.停止它是另一个故事.
我使用循环运行[runLoop run].
如果我尝试停止循环使用CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]),循环将不会停止.如果我使用CRunLoopRun()相反的方式启动循环,它可以工作.我还确保调用是在正确的线程(运行我的自定义运行循环的线程)上进行的.我调试了这个pthread_self().
我找到了一个邮件列表存档,开发人员说" CRunLoopStop()如果使用run方法启动循环,就不要使用NSRunLoop".我可以理解为什么它是这样的 - 你通常将初始化器和终结器配对来自同一组函数.
如何在NSRunLoop没有"诉诸CF" 的情况下停止?我没有看到stop方法NSRunLoop.文档说你可以通过三种方式停止运行循环:
CFRunLoopStop()好吧,我已经尝试过2.并且有一种"丑陋"的感觉,因为你必须深入研究CF. 3.不可能 - 我不喜欢非确定性代码.
这给我们留下了1.如果我理解正确的文档,你不能"添加"超时已经存在的运行循环.您只能在超时时运行新的运行循环.如果我运行一个新的运行循环,它将无法解决我的问题,因为它只会创建一个嵌套的运行循环.我仍然会回到原来的那个,同样我想停止......对吧?我可能误解了这个.另外,我不想使用超时值运行循环.如果我这样做,我将不得不在刻录CPU周期(低超时值)和响应性(高超时值)之间进行权衡.
这是我现在的设置(伪代码):
Communicator.h
@interface Communicator : NSObject {
NSThread* commThread;
}
-(void) start;
-(void) stop;
@end
Run Code Online (Sandbox Code Playgroud)
Communicator.m
@interface Communicator (private)
-(void) threadLoop:(id) argument;
-(void) stopThread;
@end
@implementation Communicator
-(void) start {
thread = [[NSThread alloc] initWithTarget:self
selector:@selector(threadLoop:)
object:nil];
[thread start];
}
-(void) stop …Run Code Online (Sandbox Code Playgroud) 我正在使用第三方框架在Swift中编写命令行应用程序(如果我理解正确的代码)依赖于GCD回调来在套接字接收数据时完成某些操作.为了更好地理解框架,我一直在使用框架作者编写的示例Cocoa应用程序来与框架一起使用.
因为示例应用程序是Cocoa应用程序,所以自动处理运行循环.我在示例应用程序(MIT许可证)中包含代码片段,以了解它是如何工作的:
class AppDelegate: NSObject, NSApplicationDelegate {
var httpd : Connect!
func startServer() {
httpd = Connect()
.onLog {
[weak self] in // unowned makes this crash
self!.log($0)
}
.useQueue(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))
Run Code Online (Sandbox Code Playgroud)
...
httpd.listen(1337)
}
Run Code Online (Sandbox Code Playgroud)
...
func applicationDidFinishLaunching(aNotification: NSNotification?) {
startServer()
...
}
}
Run Code Online (Sandbox Code Playgroud)
我想修改示例应用程序以从命令行运行.当我将startServer()函数放入命令行应用程序时,它会运行,但是套接字在打开后立即关闭,并且程序以退出代码0完成执行.这是预期的行为,因为没有运行循环在Xcode命令行项目中,因此程序不知道等待套接字接收数据.
我相信让套接字保持打开的正确方法是连续运行程序将主线程放在CFRunLoop中.我查看了Apple的文档,除了基本的API参考,Swift中没有任何线程.我查看了第三方资源,但它们都涉及iOS和Cocoa应用程序中的备用线程.如何正确实现主线程的CFRunLoop?
我在一个线程中有一个连接,所以我将它添加到运行循环中以获取所有数据:
[[NSRunLoop currentRunLoop] run];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
Run Code Online (Sandbox Code Playgroud)
但我找不到任何阻止它的方法
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
if([NSRunLoop currentRunLoop]){
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget:self];
}
[connection cancel];
}
Run Code Online (Sandbox Code Playgroud)
我怎么能阻止这个循环呢?
我的(主要是POSIX)应用程序的Mac构建产生一个子线程,它调用CFRunLoopRun()来执行事件循环(从MacOS获取网络配置更改事件).
当打包并离开时,主线程在子线程的运行循环上调用CFRunLoopStop(),此时CFRunLoopRun()在子线程中返回,子线程退出,主线程(这是阻止等待子线程退出)可以继续.
这似乎有效,但我的问题是:这是一种安全/推荐的方式吗?特别是,从另一个线程调用CFRunLoopStop()容易导致竞争条件?据我所知,Apple的文档对此主题保持沉默.
如果从主线程调用CFRunLoopStop()不是解决方案,那么什么是好的解决方案?我知道我可以让子线程调用CFRunLoopRunInMode()并经常唤醒以检查布尔值或其他东西,但我宁愿不让子线程做任何轮询,如果我可以避免它.
我正在关注iOS"音频队列编程指南 - 播放音频".在指南的末尾,可以CFRunLoopRunInMode()在步骤Start和Run a Audio Queue中调用:
do { // 5
CFRunLoopRunInMode ( // 6
kCFRunLoopDefaultMode, // 7
0.25, // 8
false // 9
);
} while (aqData.mIsRunning);
//...
Run Code Online (Sandbox Code Playgroud)
第6行的文档说:"CFRunLoopRunInMode函数运行包含音频队列线程的运行循环." 但是,当我的方法返回时,是不是执行了运行循环?上面的代码是在我的应用程序中按下播放按钮时由主线程执行的.
现在我很难理解这些调用CFRunLoopRunInMode()有什么好处,因为它们的缺点是我的播放按钮没有正确更新(它看起来整个音频播放的时候按下了)并且没有正面效果,即如果我从我的代码中删除do-while-loop以及调用CFRunLoopRunInMode()而直接从此方法返回,则音频也可以很好地播放.那么这就指出了显而易见的解决方案,只需将这些调用删除,因为这不会产生问题.有人可以解释为什么苹果公司在使用iOS中的音频队列进行音频播放的官方指南中包含此代码吗?
编辑:
我只是在Mac OS X中看到,存在与iOS相同的音频队列API,iOS指南似乎是Mac OS指南的复制粘贴复制品.这让我怀疑那些对运行循环的调用仅在Mac OS中需要而在iOS中不再需要,例如因为否则Mac OS应用程序会退出或类似的东西.有人可以验证这个或排除它吗?
我有以下代码
private func addRunLoopObserverForSaving() {
var _self = self
withUnsafeMutablePointer(&_self) { (pSelf) -> Void in
var observerContext = CFRunLoopObserverContext(
version: 0,
info: pSelf,
retain: nil,
release: nil,
copyDescription: nil)
withUnsafeMutablePointer(&observerContext, { (pObserverContext) -> Void in
let observer = CFRunLoopObserverCreate(
kCFAllocatorDefault,
CFRunLoopActivity.BeforeTimers.rawValue,
true,
0,
{ (observer, activity, context) -> Void in
guard context != nil else { return }
let pObserverContext = UnsafeMutablePointer<CFRunLoopObserverContext>(context)
let pGraphsModel = UnsafeMutablePointer<GraphsModel>(pObserverContext.memory.info)
let z = pGraphsModel.memory
...
},
pObserverContext
)
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode)
})
}
} …Run Code Online (Sandbox Code Playgroud) 我有一个无限循环驱动我的工作线程.
-(void) myThread
{
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
while(![myThread isCancelled])
{
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:600]];
}
[pool release];
}
Run Code Online (Sandbox Code Playgroud)
但有时候这些线程占用了很多CPU(50-100%)和内存(1.5GB).当我在这种状态下对应用程序进行采样时,我得到了以下跟踪
453 +[NSDate dateWithTimeIntervalSinceNow:]
309 -[__NSPlaceholderDate initWithTimeIntervalSinceReferenceDate:]
295 CFDateCreate
268 _CFRuntimeCreateInstance
115 malloc_zone_malloc
64 __spin_lock
64 __spin_lock
43 szone_malloc
22 tiny_malloc_from_free_list
22 tiny_malloc_from_free_list
19 szone_malloc
2 spin_unlock
2 spin_unlock
4 malloc_zone_malloc
3 dyld_stub__spin_unlock
3 dyld_stub__spin_unlock
1 dyld_stub__spin_lock
1 dyld_stub__spin_lock
99 __bzero
99 __bzero
29 malloc_size
23 szone_size
23 szone_size
6 malloc_size
13 CFAllocatorAllocate
13 CFAllocatorAllocate
12 _CFRuntimeCreateInstance
20 CFDateCreate
4 CFDateGetTypeID …Run Code Online (Sandbox Code Playgroud) 我正在尝试订阅 macOS 上电源状态的更改。我发现有一种使用 IOKit 的方法,尽管它有点复杂。我需要#import <IOKit/ps/IOPowerSources.h>在 ObjC 桥接标头中使用它来导入它。然后我可以访问函数 IOPSNotificationCreateRunLoopSource,其签名为:
IOPSNotificationCreateRunLoopSource(_ callback: IOPowerSourceCallbackType!, _ context: UnsafeMutablePointer<Void>!) -> Unmanaged<CFRunLoopSource>!
Run Code Online (Sandbox Code Playgroud)
我从Callback method to Apple run Loop的答案中得到了一些帮助,但仍然无法IOPowerSourceCallbackType在 Swift 中创建类型的函数。编译此程序时缺少什么?
我已经阅读了CFRunLoop,但仍然有点困惑.我来了一段代码,我想为自己澄清一下:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:url]]];
[request setHTTPMethod:@"POST"];
[request setValue:@"application/xml" forHTTPHeaderField:@"Content-Type"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody:postData];
[[NSURLConnection alloc]initWithRequest:request delegate:self];
CFRunLoopRun();
Run Code Online (Sandbox Code Playgroud)
所以,假设这一切都在主线程上被调用,它会阻塞主线程吗?或者它会通过CFRunLoopRun()函数调用生成一个新线程吗?
谢谢!
我有以下类使用Mono(在mac中)将一些运行循环调用从本机代码映射到C#,并且编译器不起作用,它在尝试编译时一直崩溃.我已将其删除到仅包含此类的单独项目,但它仍然已损坏,因此看起来问题是具体使用此代码.
有没有人见过这样的东西?
using System;
using System.Threading;
namespace Integration.Mac
{
public class CommonRunLoop
{
static IntPtr runLoopReference;
public static IntPtr CommonRunLoopReference {
get {
return runLoopReference;
}
}
static CommonRunLoop() {
AutoResetEvent lockObj = new AutoResetEvent (true);
Thread runLoop = new Thread (delegate() {
runLoopReference = CFRunLoopGetCurrent ();
lockObj.Set ();
CFRunLoopRun ();
});
runLoop.IsBackground = true;
runLoop.Name = "Common-Sync-Run-Loop";
lockObj.WaitOne();
}
[DllImport ("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")]
extern static IntPtr CFRunLoopGetCurrent ();
[DllImport ("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")]
extern static IntPtr CFRunLoopGetMain ();
[DllImport ("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")]
extern static …Run Code Online (Sandbox Code Playgroud) cfrunloop ×10
nsrunloop ×3
swift ×3
cocoa ×2
ios ×2
macos ×2
objective-c ×2
c ×1
c# ×1
c++ ×1
callback ×1
cocoa-touch ×1
foundation ×1
interop ×1
iokit ×1
macos-carbon ×1
mono ×1
playback ×1
types ×1
xcode7 ×1