我正在编写一个必须与通过USB连接的设备进行通信的应用程序.应用程序在固定时间从设备轮流发送和接收数据.所有Rx/Tx都发生在一个单独的线程中,否则UI将被阻止.基本结构看起来基本上是这样的.(自动释放池和省略的东西)
-(void)comThread:(id)arg {
while(state == kIsConnected) {
// let timers run
[runLoop runUntilDate:[NSDate distantFuture]];
// handle data
if(rxTxState == kRx) {
// do some stuff to pass data to upper layers
rxTxState = kTx;
}
if(rxTxState == kTx) {
// do some stuff to send data
rxTimeoutTimer = [NSTimer scheduledTimer....];
}
}
}
Run Code Online (Sandbox Code Playgroud)
在发送数据之后,应用程序等待接收数据或者rxTimeoutTimer发送导致重新发送数据包的数据.rx操作有效,因为底层使用异步系统调用并调用一个看起来基本像这样的rx处理程序.
-(void)receiveData:(NSData*)data{
[rxQueue addObject:data];
[rxTimeoutTimer invalidate]; // cancel timeout
}
Run Code Online (Sandbox Code Playgroud)
有一种(简单的)[runLoop runUntilDate:]退出方式receiveData:吗?Apple文档说删除所有计时器源并不能保证RunLoop退出.我读了一些关于打电话的事情,performSelector:onThread:...但它要么不起作用,要么我没有明白这一点.
谢谢.
请考虑以下代码:
在第一个中,我调用一个创建动画的函数.我以一定的时间间隔做到这一点:
start:;
[self animationMethod];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
//sleep(3);
goto start;
Run Code Online (Sandbox Code Playgroud)
在第二个我创建一个动画
- (void)animationMethod
{
CAKeyframeAnimation *myAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGPathMoveToPoint(curvedPath, NULL, start.x, start.y);
CGPathAddCurveToPoint(curvedPath, NULL, fcp.x, fcp.y, scp.x , scp.y, end.x, end.y);
myAnimation.path = curvedPath;
myAnimation.duration = flight_duration;
myAnimation.removedOnCompletion = NO;
myAnimation.delegate = self;
myAnimation.fillMode = kCAFillModeForwards;
[myAnimation setValue:identifier forKey:@"id"];
[flyingBug addAnimation:myAnimation forKey:@"bug_flight"];
CGPathRelease(curvedPath);
}
Run Code Online (Sandbox Code Playgroud)
第三个是委托方法,我用来检查一切正常:
- (void)animationDidStart:(CAAnimation *)anim
{
NSLog(@"ANIMATION DID START");
}
Run Code Online (Sandbox Code Playgroud)
因此,当我使用NSRunLoop它工作正常时,调用委托方法,但如果我尝试使用sleep(3)函数,那么委托方法不会被调用.
我的问题:
1)你能解释一下NSRunLoop和sleep()之间的区别吗?为什么在使用sleep()时不调用委托方法?
2)也许第三种可能的方法更好用?
我有一个无限循环驱动我的工作线程.
-(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) 我有以下代码:
- (void)test_with_running_runLoop {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSTimeInterval checkEveryInterval = 0.05;
NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue());
dispatch_async(dispatch_get_main_queue(), ^{
sleep(1);
NSLog(@"I will reach here, because currentRunLoop is run");
dispatch_semaphore_signal(semaphore);
});
while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW))
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:checkEveryInterval]];
NSLog(@"I will see this, after dispatch_semaphore_signal is called");
}
- (void)test_without_running_runLoop {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue());
dispatch_async(dispatch_get_main_queue(), ^{
sleep(1);
NSLog(@"I will not reach here, because currentRunLoop is not run");
dispatch_semaphore_signal(semaphore);
}); …Run Code Online (Sandbox Code Playgroud) 我读了关于runloop的这个苹果文档:
运行循环是一个事件处理循环,用于调度工作并协调传入事件的接收...运行循环从两种不同类型的源接收事件.输入源提供异步事件...定时器源提供同步事件......
现在我知道performSelector:withObject:afterDelay:并NSTimer在runloop中运行.
该文档未提及触摸事件作为输入源.我想知道:
Q1:[UIApplication sendEvent:]在某些默认的runloop中也会通过run 发送触摸事件吗?
Q2:如果Q1的答案为YES,那么默认的runloop是否是相同的runloop句柄performSelector:withObject:afterDelay:和NSTimer事件?
我购买了 Objective-C 的 Big Nerd Ranch Guide,但有一些NSRunLoop我想不通的地方。
这是书中的一段代码:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:logger
selector:@selector(updateLastTime:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] run];
Run Code Online (Sandbox Code Playgroud)
我的问题是,为什么我需要为要处理NSRunLoop的NSTimer对象放置一个?为什么它需要在最后,而不是开始?
为什么它不像其他函数或对象的方法那样我只需要调用一个函数来处理它并登录到控制台?
我真的很想弄清楚这里每个细节的每个逻辑。
假设我有 2 个线程,一个是主线程,另一个是辅助线程。主线程使用得最多,但有时(很少)我希望辅助线程根据主线程的调用做一些工作。大多数时候辅助线程应该休眠。现在经过一些搜索,我明白了这样做的方法是使用 runLoops。所以我试图阅读苹果的文档(http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW5 )
但在我看来它非常复杂,我在那里过得很艰难。有没有一种优雅而简单的方法来实现我所描述的?我可以运行和使用任何类似的 runLoop 代码示例吗?
谢谢
我有一个实现自定义的库UIControl,其方法是.valueChanged在调用时触发事件.我想测试该行为的方法.
我的自定义控件:
class MyControl: UIControl {
func fire() {
sendActions(for: .valueChanged)
}
}
Run Code Online (Sandbox Code Playgroud)
而且测试:
import XCTest
class ControlEventObserver: NSObject {
var expectation: XCTestExpectation!
init(expectation anExpectation: XCTestExpectation) {
expectation = anExpectation
}
func observe() {
expectation.fulfill()
}
}
class Tests: XCTestCase {
func test() {
let myExpectation = expectation(description: "event fired")
let observer = ControlEventObserver(expectation: myExpectation)
let control = MyControl()
control.addTarget(observer, action: #selector(ControlEventObserver.observe), for: .valueChanged)
control.fire()
waitForExpectations(timeout: 1) { error in
XCTAssertNil(error)
}
}
}
Run Code Online (Sandbox Code Playgroud)
问题是observe …
为什么print("2")在下面的代码中永远不会调用该部分?我认为内部main.async会将块推入主循环的队列中,然后RunLoop.run执行它,但显然情况并非如此。(它打印1、run、run、run等)
另外,如果我删除外部块main.async,然后直接运行该块中的代码(仍在主队列上,在viewDidLoad新的单视图应用程序中),那么内部main.async块就会被执行(打印1,,run)2。为什么这一变化会产生如此大的差异?
var x = -1
DispatchQueue.main.async { // comment out this line for question #2
print("1")
x = 1
DispatchQueue.main.async {
print("2")
x = 2
}
while x == 1 {
print("run")
RunLoop.main.run(mode: .default, before: Date() + 1)
}
} // comment out this line for question #2
Run Code Online (Sandbox Code Playgroud)