我目前正在开发一个iPhone应用程序,我有一个来自第三方的库,它有异步行为,但是我想用自己的类包装并使它看起来是同步的.
这个库中的中心类,我们称之为Connection类,有几个函数在调用委托类的实例上的方法时解析它们的最终结果.我正在尝试做的是包装这个类和委托,使它看起来是同步的而不是异步的.如果我在Java中这样做,我会使用FutureTask或CountdownLatch或只是join().但我不确定目标C中最好的方法.
我首先创建了一个NSThread扩展,NFCThread,它符合上面提到的委托协议.我的想法是我将init和NFCThread,将NFCThread实例传递给Connection的setDelegate方法,启动线程然后在Connection上调用异步方法.我的期望是NFCThread实例上的三个委托方法之一将被调用,最终导致线程退出.
为了模拟连接,我做了以下操作.我在NFCThread中添加了一个NSConditionalLock:
joinLock = [[NSConditionLock alloc] initWithCondition:NO];
Run Code Online (Sandbox Code Playgroud)
调用Connection的代码看起来像这样:
NFCThread *t = [[NFCThread alloc] init];
[connection setDelegate:t];
[t start];
[connection openSession];
// Process errors, etc...
[t.joinLock lockWhenCondition:YES];
[t.joinLock unlock];
[t release];
[connection setDelegate:nil];
Run Code Online (Sandbox Code Playgroud)
委托的协议有三种方法.在NFCThread中我实现了每个方法,如下所示:
- (void)didReceiveMessage:(CommandType)cmdType
data:(NSString *)responseData
length:(NSInteger)length {
NSLog(@"didReceiveMessage");
// Do something with data and cmdType...
[joinLock lock];
[joinLock unlockWithCondition:YES];
callBackInvoked = YES;
}
Run Code Online (Sandbox Code Playgroud)
我重载了NFCThread的主要方法,以便它不断循环.像这样的东西:
while (!callBackInvoked) { ; }
Run Code Online (Sandbox Code Playgroud)
我发现这不是一个好主意,因为它会导致cpu使用率通过屋顶.所以我尝试使用我在这个网站上找到的一些例子的运行循环:
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (!callBackInvoked) {
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; …Run Code Online (Sandbox Code Playgroud) 问题是player.status AVPlayerStatusReadyToPlay在player.currentItem.status返回之前返回完整的2秒AVPlayerItemStatusReadyToPlay.有没有人对为什么会这样做有任何有用的解释?
这只是示例代码,以显示正在发生的事情的基本概念,所以如果有任何拼写错误或其他什么请忽略它们.
- (void) someMethod
{
player = [[AVPlayer alloc] initWithURL:someValidURL];
[player play];
NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(checkStatus:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}
- (void) checkStatus: (NSTimer *)timer
{
NSLog(@"player status: %i", player.status]);
NSLog(@"player item status: %i", player.currentItem.status]);
}
Run Code Online (Sandbox Code Playgroud) 我做了一个url-Request并等待答案
我启动请求,然后等待,直到synchronousOperationComplete = TRUE
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (!synchronousOperationComplete && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
Run Code Online (Sandbox Code Playgroud)
然后我回复了
一切似乎都没问题,我得到了回应,一切正常,但当我关闭应用程序时,我得到:
bool _WebTryThreadLock(bool), 0x227f40: Multiple locks on web thread not allowed! Please file a bug. Crashing now...
1 _ZL17_WebTryThreadLockb
2 _ZL14WebRunLoopLockP19__CFRunLoopObservermPv
3 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
4 __CFRunLoopDoObservers
5 __CFRunLoopRun
6 CFRunLoopRunSpecific
7 CFRunLoopRunInMode
8 _ZL12RunWebThreadPv
9 _pthread_start
10 thread_start
Run Code Online (Sandbox Code Playgroud)
它似乎是NSRunLoop导致错误的原因,当我推荐它时,错误没有出现.
我使用IOS 5.0确实有人知道我可以做些什么来避免这个错误?
我在IOS 4.3和IOS5 Beta中使用它,它工作正常.
但我把我的tomcat6移动到另一台服务器,也许这是服务器的错误
THX mBax
使用一些代码,我遇到了运行循环,我是新手,在NSOperations 里面.
他们NSOperation正在忙于下载数据 - 当他们忙碌时,会有代码等待下载完成,以NSRunLoops和线程休眠的形式.
我特别感兴趣的是这段代码:
while (aCertainConditionIsTrue && [self isCancelled]==NO) {
if(![[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]){
[NSThread sleepForTimeInterval:1.0];
}
}
Run Code Online (Sandbox Code Playgroud)
我已经阅读了关于运行循环的信息,runMode:beforeDate:并将等待输入源或超时.虽然我不是百分之百的东西.
在第一次执行时,它总是返回NO并命中sleepForTimeInterval:.这不好吗?
在一个特定的实用程序类中,它经常会sleepForTimeInterval:遇到很多 - 每个线程一次 - 这会严重损害性能.
对此有什么更好的解决方案或建议吗?
objective-c nsoperation grand-central-dispatch nsrunloop ios
我的应用跟踪用户CLLocationManager.在委托电话中,didUpdateToLocation我做了所有有趣的事情来保存他们的位置.但是,我需要一种方法来测试它们是否已停止.我可以停止记录位置并考虑他们的旅行.所以我有一个NSTimer在CCLocationManager那个被添加,每次取出didUpdateToLocation被调用.当用户停止并CLLocationManager停止被叫时,它将被启动.
我能够完成NSTimer工作的唯一方法是:
[[NSRunLoop mainRunLoop] addTimer:userStoppedMovingTimer forMode:NSRunLoopCommonModes];
Run Code Online (Sandbox Code Playgroud)
然后删除它:
[userStoppedMovingTimer invalidate];
Run Code Online (Sandbox Code Playgroud)
我以前从来没有像这样添加计时器.有人可以解释为什么会这样吗?
我没有找到任何可以解释NSStream线程化过程的文档.具体来说,让我们去NSInputStream.在Objective-C中对我的线程目前是一个谜,因为它看起来如此简单.
我的问题主要是指这一行:
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
Run Code Online (Sandbox Code Playgroud)
您可以指定输入流将运行的运行循环,我认为这很酷.问题是,如果我希望输入和输出流在他们自己的线程中运行,并且两者都在单个类中实例化,比如Connection,那么如何让它们在自己的线程中运行?
我问的原因是因为代表们.以前我们已经完成了[inputStream setDelegate:self]这意味着我们必须声明stream:handleEvent处理传入/传出数据.
所以最后我的问题是,如果你有一个设置输入和输出流的类,你如何将每个流线程化并将处理流事件的责任委托给当前的类?
这里有一些代码可供选择:
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
Run Code Online (Sandbox Code Playgroud)
我在想以下几点:
有任何想法吗?
我试图更好地了解队列及其工作原理。这个片段是为了测试他们的行为:
- (void)dispatchQueueTest
{
NSLog( @"Begin test on %@ thread", [NSThread isMainThread] ? @"main" : @"other" );
dispatch_semaphore_t s = dispatch_semaphore_create(0);
dispatch_async( dispatch_get_main_queue(), ^{
NSLog( @"Signalling semaphore" );
dispatch_semaphore_signal(s);
});
NSLog( @"Waiting for worker" );
while( dispatch_semaphore_wait( s, DISPATCH_TIME_NOW ) ) {
NSDate* timeout = [NSDate dateWithTimeIntervalSinceNow:10.f];
// Process events on the run loop
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout];
}
dispatch_release(s);
NSLog( @"All sync'd up" );
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,它会在日志中生成以下内容:
Begin test on main thread
Waiting for worker
Signalling semaphore
All sync'd up …Run Code Online (Sandbox Code Playgroud) 我有以下情况,我创建了一个 GCD 调度队列,并在其中将 an 调度NSStream到当前NSRunLoop,正如其规范中要求它发出委托事件,然后我使用[[NSRunLoop currentRunLoop run].
这会产生三种可能的情况:
创建一个串行队列,其中通过流发送初始写入消息,并且仅当存在来自NSStream对象的委托回调时才发送其他写入消息,因为尝试在不遵守此模式的情况下写入新消息(这将是可取的)将失败,因为队列被运行循环锁定。
创建一个并发队列,在该队列中消息可以自由写入流,因为发送到队列的块将与运行运行循环的块同时执行。然而,虽然希望使写入消息和运行循环并发运行,但肯定不希望必须在并发运行的队列中阻塞同时尝试写入流。
创建两个队列——一个负责保持 run loop 处于活动状态并接收 read-from-stream 回调,另一个负责向流发送异步写入消息。这看起来很理想,但是NSStream文档似乎明确指出不应尝试在调度的线程之外读取/写入流。
鉴于这些场景都不理想,如何解决这些问题?
concurrency cocoa-touch nsstream grand-central-dispatch nsrunloop
以非常严格的时间安排重复任务的最佳方法是什么(对于音乐排序足够准确和可靠)?从 Apple 文档中,很明显 NSTimer 在这个意义上是不可靠的(即“计时器不是实时机制”)。我从 AudioKit 的AKPlaygroundLoop借用的一种方法在大约 4 毫秒内似乎是一致的(如果不是很准确),并且可能是可行的:
class JHLoop: NSObject{
var trigger: Int {
return Int(60 * duration) // 60fps * t in seconds
}
var counter: Int = 0
var duration: Double = 1.0 // in seconds, but actual loop is ~1.017s
var displayLink: CADisplayLink?
weak var delegate: JHLoopDelegate?
init(dur: Double) {
duration = dur
}
func stopLoop() {
displayLink?.invalidate()
}
func startLoop() {
counter = 0
displayLink = CADisplayLink(target: self, selector: "update")
displayLink?.frameInterval = …Run Code Online (Sandbox Code Playgroud) 有谁知道如何使用 Swift 语言将自定义输入源附加到运行循环?我正在关注这个文档:特别是运行循环:“配置运行循环源”,但我还没有弄清楚如何快速使用它。
nsrunloop ×10
objective-c ×6
nstimer ×3
ios ×2
nsstream ×2
swift ×2
avplayer ×1
cocoa ×1
cocoa-touch ×1
concurrency ×1
input ×1
iphone ×1
nsoperation ×1