魅蓝3s计步器note6的计步器还有没有得救

联博娱乐怎么样-百度知道
联博娱乐怎么样-百度知道
联博娱乐怎么样-百度知道
  我曾经在外地上班的时候,认识了一个老乡,觉得很亲切,偶尔和他一起出去逛逛,因为我们都比较忙,所以见面的次数也很少,不知道什么,当时对他比较迷恋,而他对我是什么感觉,我也不清楚。有一天,我在加班,他来到我的单位门口找我,让我出去陪他,那时候的自己没有谈过恋爱,也没有经验,总感觉自己情商很低,然后就答应陪他,我们去了宾馆,各种爱抚和吻,但没有发生关系。第一次觉得这种感觉很奇妙,然后就各自忙各自的。再过了有半个月吧,他给我发信息说,他工作压力很大,很累,要我陪他好好的聊聊,只想抱抱我,听到这话,我真的学得有点心疼他,然后就答应了,去宾馆找他,一进去他就向我诉说了他的压力。然后就开始抱着吻我,我各种阻止,还是没有阻止住,就这样和他不明不白的发生了关系,那也是我人生的第一次。从那之后我问他我们到底什么关系,他就那种唐塞,之后我就彻底和他断了联系,打电话也不接,一想起来就觉得自己很傻,很恨自己,觉得他一直是利用自己来满足自己的私欲,大家想骂我就骂吧。这些话憋了好几年也没地方说,今天终于找到这个树洞让我都吐出来吧。  我曾经在外地上班的时候,认识了一个老乡,觉得很亲切,偶尔和他一起出去逛逛,因为我们都比较忙,所以见面的次数也很少,不知道什么,当时对他比较迷恋,而他对我是什么感觉,我也不清楚。有一天,我在加班,他来到我的单位门口找我,让我出去陪他,那时候的自己没有谈过恋爱,也没有经验,总感觉自己情商很低,然后就答应陪他,我们去了宾馆,各种爱抚和吻,但没有发生关系。第一次觉得这种感觉很奇妙,然后就各自忙各自的。再过了有半个月吧,他给我发信息说,他工作压力很大,很累,要我陪他好好的聊聊,只想抱抱我,听到这话,我真的学得有点心疼他,然后就答应了,去宾馆找他,一进去他就向我诉说了他的压力。然后就开始抱着吻我,我各种阻止,还是没有阻止住,就这样和他不明不白的发生了关系,那也是我人生的第一次。从那之后我问他我们到底什么关系,他就那种唐塞,之后我就彻底和他断了联系,打电话也不接,一想起来就觉得自己很傻,很恨自己,觉得他一直是利用自己来满足自己的私欲,大家想骂我就骂吧。这些话憋了好几年也没地方说,今天终于找到这个树洞让我都吐出来吧。
  信网6月13日讯信网了解到,近日,市民王先生到市南区市场监管局湛山所进行投诉,述说自己花费17000元报名参加了一家宣称考试可以一次性保过关的培训机构办的医师证资格证书培训班,但是经过一段时间培训,结果考试未能通过。他找到培训机构,要求退还学费,培训班负责人却以其未能认真学习课程为由,拒不退还学费。   王先生认为自己已经非常努力,他提供出了学习课程的相关登陆信息,签到记录,从相关证据来看,王先生的确一节课也没有缺勤,不能说不努力。而且,培训机构发放的内部资料也确实按时进行了领取。而培训机构不仅没有像当初承诺的按期考取医师证,反而要付出高昂的学费,王先生认为培训机构违反合同约定,推托责任,要求市场监管部门帮助其讨回公道。   湛山所工作人员石爱军、陈扬在了解了投诉人相关诉求后,与该培训机构负责人进行联系。负责人辨称,当初入学时双方确实签订了一份协议,协议明确承诺如果不能通过考试就退还所有学费。可是,前提是学员必须认真学习所有课程资料,而培训班提供的学习资料里押中大多数考试题,其他学员都能够通过,王先生肯定是没有按照协议约定认真学习。   所以,该培训机构拒绝退还学费。工作人员组织双方进行调解,王先生将签到记录,课程登陆、资料领取参加学习记录一一提供出来,与培训机构进行争论,双方各执一词,互不退让。   工作人员根据双方提供的合同协议和证据材料认为,协议清楚地标明学员需要认真学习所有课程、资料,同时,培训机构承诺在学员考试失败后退还学费。以及培训机构对王先生提供参加培训的证据,也表示认可。   但培训机构对王先生是否进行了认真的熟读和背诵相关资料,还是背诵后依然无法熟练掌握提出质疑。工作人员认为,培训机构既然已收取高额培训费用,应对学员学习情况实施监督、跟踪,督促、帮助学员熟练掌握学习知识。培训机构仅用未认真学习为由,不退学费,缺少依据。面对王先生未能取得资格证书的事实,这是无可辩驳的,以未按要求进行学习为由不退学费,是不合适的,合同既然约定未过退款,应依法履约。   在调解人员有理有据的调解下,培训机构的强硬态度有了转变,当即表示愿意退还学费,一起“保过班不保过”引起的纠纷顺利解决。   当今社会,随着各种考试的增多,许多培训机构利用考生的心理推出各种五花八门的“保过班”,有些保过班通过高强度的学习训练,雄厚的师资力量,的确提高了通过率,但是有些保过班却打着“内部资料”的幌子,行走在法律边缘,骗取考生钱财。市南区市场监管局提醒,在进行培训机构报名时,一定要认真研读协议合同,谨慎签署。另外,切忌偷奸耍滑的侥幸心理,无论是什么考试,都需要踏踏实实,认真地学习,千万莫走捷径。   来源:信网
责任编辑:张建利
阅读:3846
推荐文章RECOMMENDNSTimer和实现弱引用的timer的方式
招聘信息:
本文是投稿文章,作者:&目录我们常用NSTimer的方式上面的NSTimer无论采用何种方式都是在主线程上跑的那么怎么在非主线程中跑一个NSTimer呢GCD的方式一次性的timer方式的GCD模式另一种dispatch_after方式的定时器利用GCD的弱引用型的timer使用NSTimer方式创建的Timer使用时候需要注意参考文档如下代码所示,是我们最常见的使用timer的方式@property&(nonatomic&,&strong)&NSTimer&*animationTself.animationTimer&=&[NSTimer&scheduledTimerWithTimeInterval:(self.animationDuration&=&animationDuration)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&target:self
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&selector:@selector(animationTimerDidFired:)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&userInfo:nil
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&repeats:YES];123456当使用NSTimer的scheduledTimerWithTimeInterval方法时。事实上此时Timer会被加入到当前线程的Run Loop中,且模式是默认的NSDefaultRunLoopMode。而如果当前线程就是主线程,也就是UI线程时,某些UI事件,比如UIScrollView的拖动操作,会将Run Loop切换成NSEventTrackingRunLoopMode模式,在这个过程中,默认的NSDefaultRunLoopMode模式中注册的事件是不会被执行的。也就是说,此时使用scheduledTimerWithTimeInterval添加到Run Loop中的Timer就不会执行。我们可以通过添加一个UICollectionView,然后滑动它后打印定时器方法&11:41:59.770&TimerAbout[9]&enter&timer
&11:42:00.339&TimerAbout[9]&enter&timer
&11:42:01.338&TimerAbout[9]&enter&timer
&11:42:02.338&TimerAbout[9]&enter&timer
&11:42:03.338&TimerAbout[9]&enter&timer
&11:42:15.150&TimerAbout[9]&enter&timer
&11:42:15.338&TimerAbout[9]&enter&timer从中可以看到,当UICollectionView滑动时候,定时器方法并没有打印(从03.338到15.150)为了设置一个不被UI干扰的Timer,我们需要手动创建一个Timer,然后使用NSRunLoop的addTimer:forMode:方法来把Timer按照指定模式加入到Run Loop中。这里使用的模式是:NSRunLoopCommonModes,这个模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的结合,还是上面的例子,换为:self.animationTimer&=&[NSTimer&timerWithTimeInterval:1&target:self&selector:@selector(animationTimerDidFired:)&userInfo:nil&repeats:YES];
&&&&[[NSRunLoop&mainRunLoop]&addTimer:self.animationTimer&forMode:NSRunLoopCommonModes];12则,无论你滑动不滑动UICollectionView,定时器都是起作用的!上面的NSTimer无论采用何种方式,都是在主线程上跑的,那么怎么在非主线程中跑一个NSTimer呢?我们简单的可以使用如下代码://创建并执行新的线程
&&&&NSThread&*thread&=&[[NSThread&alloc]&initWithTarget:self&selector:@selector(newThread)&object:nil];
&&&&[thread&start];
-&(void)newThread
&&&&@autoreleasepool
&&&&{&&&&&&&&//在当前Run&Loop中添加timer,模式是默认的NSDefaultRunLoopMode
&&&&&&&&[NSTimer&scheduledTimerWithTimeInterval:1.0&target:self&selector:@selector(animationTimerDidFired:)&userInfo:nil&repeats:YES];&&&&&&&&//开始执行新线程的Run&Loop
&&&&&&&&[[NSRunLoop&currentRunLoop]&run];
}1121314当然了,因为是开启的新的线程,在定时器的回调方法中,需要切换到主线程才能操作UI。GCD的方式//GCD方式
&&&&uint64_t&interval&=&1&*&NSEC_PER_SEC;
&&&&//创建一个专门执行timer回调的GCD队列
&&&&dispatch_queue_t&queue&=&dispatch_queue_create("timerQueue",&0);
&&&&_timer&=&dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,&0,&0,&queue);
&&&&//使用dispatch_source_set_timer函数设置timer参数
&&&&dispatch_source_set_timer(_timer,&dispatch_time(DISPATCH_TIME_NOW,&0),&interval,&0);
&&&&//设置回调
&&&&dispatch_source_set_event_handler(_timer,&^(){
&&&&&&&&NSLog(@"Timer&%@",&[NSThread&currentThread]);
&&&&dispatch_resume(_timer);//dispatch_source默认是Suspended状态,通过dispatch_resume函数开始它112其中的dispatch_source_set_timer的最后一个参数,是最后一个参数(leeway),它告诉系统我们需要计时器触发的精准程度。所有的计时器都不会保证100%精准,这个参数用来告诉系统你希望系统保证精准的努力程度。如果你希望一个计时器每5秒触发一次,并且越准越好,那么你传递0为参数。另外,如果是一个周期性任务,比如检查email,那么你会希望每10分钟检查一次,但是不用那么精准。所以你可以传入60,告诉系统60秒的误差是可接受的。他的意义在于降低资源消耗。一次性的timer方式的GCD模式dispatch_after(dispatch_time(DISPATCH_TIME_NOW,&(int64_t)(1&*&NSEC_PER_SEC)),&dispatch_get_main_queue(),&^{&&&&&&&&NSLog(@"dispatch_after&enter&timer");
&&&&});123另一种dispatch_after方式的定时器这个是使用上面的dispatch_after来创建的,通过递归调用来实现。-&(void)dispatechAfterStyle&{
&&&&__weak&typeof&(self)&wself&=&
&&&&dispatch_after(dispatch_time(DISPATCH_TIME_NOW,&(int64_t)(1&*&NSEC_PER_SEC)),&dispatch_get_main_queue(),&^{
&&&&&&&&NSLog(@"dispatch_after&enter&timer,thread&=&%@",&[NSThread&currentThread]);
&&&&&&&&[wself&dispatechAfterStyle];
}利用GCD的弱引用型的timer实现了一个利用GCD的弱引用的timer。原理是利用一个新的对象,在这个对象中:NSString&*privateQueueName&=&[NSString&stringWithFormat:@"com.mindsnacks.msweaktimer.%p",&self];
&&&&&&&&self.privateSerialQueue&=&dispatch_queue_create([privateQueueName&cStringUsingEncoding:NSASCIIStringEncoding],&DISPATCH_QUEUE_SERIAL);
&&&&&&&&dispatch_set_target_queue(self.privateSerialQueue,&dispatchQueue);
&&&&&&&&self.timer&=&dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&0,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&0,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&self.privateSerialQueue);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
-&(void)resetTimerProperties
&&&&int64_t&intervalInNanoseconds&=&(int64_t)(self.timeInterval&*&NSEC_PER_SEC);
&&&&int64_t&toleranceInNanoseconds&=&(int64_t)(self.tolerance&*&NSEC_PER_SEC);
&&&&dispatch_source_set_timer(self.timer,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&dispatch_time(DISPATCH_TIME_NOW,&intervalInNanoseconds),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(uint64_t)intervalInNanoseconds,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&toleranceInNanoseconds
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&);
-&(void)schedule
&&&&[self&resetTimerProperties];
&&&&__weak&MSWeakTimer&*weakSelf&=&
&&&&dispatch_source_set_event_handler(self.timer,&^{
&&&&&&&&[weakSelf&timerFired];
&&&&dispatch_resume(self.timer);
}创建了一个队列self.timer = dispatch_source_create,然后在这个队列中创建timer dispatch_source_set_timer.注意其中用到了dispatch_set_target_queue(self.privateSerialQueue, dispatchQueue); 这个是将dispatch队列的执行操作放到队列dispatchQueue 中去。这份代码中还用到了原子操作!值得好好研读,以便以后可以在自己的多线程设计中使用原子操作。为什么用原子操作呢,因为作者想的是在多线程的环境下设置定时器的开关与否。if&(OSAtomicAnd32OrigBarrier(1,&&_timerFlags.timerIsInvalidated))
if&(!OSAtomicTestAndSet(7,&&_timerFlags.timerIsInvalidated))
&&&&&&&&dispatch_source_t&timer&=&self.
&&&&&&&&dispatch_async(self.privateSerialQueue,&^{
&&&&&&&&&&&&dispatch_source_cancel(timer);
&&&&&&&&&&&&ms_release_gcd_object(timer);
&&&&&&&&});
&&&&}至于其中&struct
&&&&&&&&uint32_t&timerIsI
&&&&}&_timerF这里为什么要用结构体呢?为什么不直接使用一个uint32_t 的变量?使用NSTimer方式创建的Timer,使用时候需要注意。由于self.animationTimer&=&[NSTimer&scheduledTimerWithTimeInterval:1
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&target:self
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&selector:@selector(animationTimerDidFired:)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&userInfo:nil
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&repeats:YES];会导致timer 强引用 self,而animationTimer又是self的一个强引用,这造成了强引用的循环了。&如果不手工停止timer,那么self这个VC将不能够被释放,尤其是当我们这个VC是push进来的时候,pop将不会被释放!!!&怎么解决呢?当然了,可以采用上文提到的可是如果有时候,我们不想使用它,觉得它有点复杂呢?1.在VC的disappear方法中应该调用 invalidate方法,将定时器释放掉,这里可能有人要说了,我直接在vc的dealloc中释放不行么?-(void)dealloc&{
[_animationTimer&invalidate];
}很遗憾的告诉你,都已经循环引用了,vc压根就释放不了,怎么调dealloc方法?在vc的disappear方法中-(void)viewWillDisappear:(BOOL)animated&{
[super&viewWillDisappear:animated];
[_animationTimer&invalidate];
}这样的确能解决问题,可是不一定是我们想要的呀,当我们vc 再push了一个新的页面的时候,本身vc没有释放,按理说,其成员timer不应该被释放呀,你可能会说,那还不容易,在appear方法中再重新生成一下呗…但是这样的话,又要增加一个变量,标识定时器在上一次disappear时候是不是启动了吧,是启动了,被invaliate的时候,才能在appear中重新启动吧。这样是不是觉得很麻烦?3.你可能会说,那简单啊,直接若引用就可以了想想我们使用block的时候@property&(nonatomic,&copy)&void&&(^&myblock)(NSInteger&i);
__weak&typeof&(self)&weakSelf&=&
self.myblock&=&^(NSInteger&i){
&&&&[weakSelf&view];
};在其中,我们需要在block中引用self,如果直接引用,也是循环引用了,采用先定义一个weak变量,然后在block中引用weak对象,避免循环引用 你会直接想到如下的方式__weak&typeof&(self)&wself&=&
self.animationTimer&=&[NSTimer&scheduledTimerWithTimeInterval:1
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&target:wself
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&selector:@selector(animationTimerDidFired:)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&userInfo:nil
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&repeats:YES];是不是瞬间觉得完美了,呵呵,我只能说少年,你没理解两者之间的区别。在block中,block是对变量进行捕获,意思是对使用到的变量进行拷贝操作,注意是拷贝的不是对象,而是变量自身。拿上面的来说,block中只是对变量wself拷贝了一份,也就是说,block中也定义了一个weak对象,相当于,在block的内存区域中,定义了一个__weak blockWeak对象,然后执行了blockWeak = wself;注意到了没,这里并没有引起对象的持有量的变化,所以没有问题,再看timer的方式,虽然你是将wself传入了timer的构造方法中,我们可以查看NSTimer的+&(NSTimer&*)timerWithTimeInterval:(NSTimeInterval)seconds&target:(id)target&selector:(SEL)aSelector&userInfo:(id)userInfo&repeats:(BOOL)repeats1定义,其target的说明The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to this object until it (the timer) is invalidated,是要强应用这个变量的 也就是说,大概是这样的,__strong strongSelf = wself&强引用了一个弱应用的变量,结果还是强引用,也就是说strongSelf持有了wself所指向的对象(也即是self所只有的对象),这和你直接传self进来是一样的效果,并不能达到解除强引用的作用!看来只能换个思路了,我直接生成一个临时对象,让Timer强用用这个临时对象,在这个临时对象中弱引用self,可以了吧。4.考虑引入一个对象,在这个对象中弱引用self,然后将这个对象传递给timer的构建方法 这里可以参考建立这个对象:@interface&YYWeakProxy&:&NSProxy
@property&(nonatomic,&weak,&readonly)&id&
-&(instancetype)initWithTarget:(id)
+&(instancetype)proxyWithTarget:(id)
@implementation&YYWeakProxy
-&(instancetype)initWithTarget:(id)target&{
_target&=&
+&(instancetype)proxyWithTarget:(id)target&{
return&[[YYWeakProxy&alloc]&initWithTarget:target];
//当不能识别方法时候,就会调用这个方法,在这个方法中,我们可以将不能识别的传递给其它对象处理
//由于这里对所有的不能处理的都传递给_target了,所以methodSignatureForSelector和forwardInvocation不可能被执行的,所以不用再重载了吧
//其实还是需要重载methodSignatureForSelector和forwardInvocation的,为什么呢?因为_target是弱引用的,所以当_target可能释放了,当它被释放了的情况下,那么forwardingTargetForSelector就是返回nil了.然后methodSignatureForSelector和forwardInvocation没实现的话,就直接crash了!!!
//这也是为什么这两个方法中随便写的!!!
-&(id)forwardingTargetForSelector:(SEL)selector&{
-&(void)forwardInvocation:(NSInvocation&*)invocation&{
void&*null&=&NULL;
[invocation&setReturnValue:&null];
-&(NSMethodSignature&*)methodSignatureForSelector:(SEL)selector&{
return&[NSObject&instanceMethodSignatureForSelector:@selector(init)];
-&(BOOL)respondsToSelector:(SEL)aSelector&{
return&[_target&respondsToSelector:aSelector];
-&(BOOL)isEqual:(id)object&{
return&[_target&isEqual:object];
-&(NSUInteger)hash&{
return&[_target&hash];
-&(Class)superclass&{
return&[_target&superclass];
-&(Class)class&{
return&[_target&class];
-&(BOOL)isKindOfClass:(Class)aClass&{
return&[_target&isKindOfClass:aClass];
-&(BOOL)isMemberOfClass:(Class)aClass&{
return&[_target&isMemberOfClass:aClass];
-&(BOOL)conformsToProtocol:(Protocol&*)aProtocol&{
return&[_target&conformsToProtocol:aProtocol];
-&(BOOL)isProxy&{
return&YES;
-&(NSString&*)description&{
return&[_target&description];
-&(NSString&*)debugDescription&{
return&[_target&debugDescription];
@end使用的时候,将原来的替换为:self.animationTimer&=&[NSTimer&scheduledTimerWithTimeInterval:1
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&target:[YYWeakProxy&proxyWithTarget:self&]
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&selector:@selector(animationTimerDidFired:)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&userInfo:nil
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&repeats:YES];5.block方式来解决循环引用@interface&NSTimer&(XXBlocksSupport)
+&(NSTimer&*)xx_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&block:(void(^)())block
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&repeats:(BOOL)
@implementation&NSTimer&(XXBlocksSupport)
+&(NSTimer&*)xx_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&block:(void(^)())block
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&repeats:(BOOL)repeats
return&[self&scheduledTimerWithTimeInterval:interval
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&target:self
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&selector:@selector(xx_blockInvoke:)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&userInfo:[block&copy]
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&repeats:repeats];
+&(void)xx_blockInvoke:(NSTimer&*)timer&{
void&(^block)()&=&timer.
if(block)&{
&&&&block();
@end注意:以上NSTimer的target是NSTimer类对象,类对象本身是个单利,此处虽然也是循环引用,但是由于类对象不需要回收,所以没有问题。但是这种方式要注意block的间接循环引用,当然了,解决block的间接循环引用很简单,定义一个weak变量,在block中使用weak变量即可。参考文档
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量10694点击量10447点击量9301点击量6461点击量5393点击量5140点击量5082点击量5002点击量4462
&2015 Chukong Technologies,Inc.
京公网安备89IOS专栏(80)
IOS入门之面试(5)
1、KVC的底层实现?
当一个对象调用setValue方法时,方法内部会做以下操作:
①检查是否存在相应key的set方法,如果存在,就调用set方法
②如果set方法不存在,就会查找与key相同名称并且带下划线的成员属性,如果有,则直接给成员属性赋值
③如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值
④如果还没找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
2、__block和__weak修饰符的区别?
1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
3.__block对象可以在block中被重新赋值,__weak不可以。
3、block和代理的区别,哪个更好?
代理回调更面向过程,block更面向结果。
如果需要在执行的不同步骤时被通知,你就要使用代理。
如果只需要请求的消息或者失败的详情,应该使用block。
block更适合与状态无关的操作,比如被告知某些结果,block之间是不会相互影响的。
但是代理更像一个生产流水线,每个回调方法是生产线上的一个处理步骤,一个回调的变动可能会引起另一个回调的变动。
要是一个对象有超过一个的不同事件,应该使用代理。
一个对象只有一个代理,要是某个对象是个单例对象,就不能使用代理。
要是一个对象调用方法需要返回一些额外的信息,就可能需要使用代理。
4、Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?
线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQ
NSThread创建线程的三种方法:
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"nil"];
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"我是分离出来的子线程"];
[self performSelectorInBackground:@selector(run:) withObject:@"我是后台线程"];
在主线程执行代码,就调用performSelectorOnMainThread方法。
如果想延时执行代码可以调用performSelector:onThread:withObject:waitUntilDone:方法;
利用异步函数dispatch_async()创建子线程。
在主线程执行代码,dispatch_async(dispatch_get_main_queue(), ^{});
延迟执行代码(延迟·可以控制代码在哪个线程执行):
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{});
NSOperationQueue:
使用NSOperation的子类封装操作,再将操作添加到NSOperationQueue创建的队列中,实现多线程。
在主线程执行代码,只要将封装代码的NSOperation对象添加到主队列就可以了。
5、控制器view的生命周期?
6、控制器View的加载过程?
当程序访问了控制器的View属性时会先判断控制器的View是否存在,如果存在就直接返回已经存在的View;
如果不存在,就会先调用loadView这个方法;如果控制器的loadView方法实现了,就会按照loadView方法加载自定义的View;
如果控制器的loadView方法没有实现就会判断storyboard是否存在;
如果storyboard存在就会按照storyboard加载控制器的View;如果storyboard不存在,就会创建一个空视图返回。
7、iOS开发中数据存储的方法?
常见存储方法有三种:plist存储、偏好设置(NSUserDefaults)和归档。
属性列表(plist)存储:
适用对象:只有带有writeToFil方法的对象才能用这种方法,比如NSString、、NSArray、NSDictionary、NSSet、NSNumber、NSData等,不能存储自定义的对象
存储方法:
调用对象的writeToFile...方法就可以写入文件
读取方法:
调用对象的...WithContentsOfFile方法就可以从文件中读取对象内容
偏好设置(NSUserDefaults):
适用对象:使用NSUserDefaults,存储用户关于应用的偏好设置,本质上仍然是plist存储,不能存储自定义的OC对象
存储方法:
利用NSUserDefaults的setObject等方法进行存储
读取方法:
利用NSUserDefaults的objectForKey等方法进行读取
归档(NSKeyedArchiver):
适用对象:可以存储自定义的对象,只有遵守了NSCoding协议的对象才可以
存储方法(归档):
调用NSKeyedArchiver的archiverRootObject: toFile: 方法存储对象,archiverRootObject执行这个方法时,底层就会调用要存的对象的encodeWithCoder方法,
调用encodeWithCoder目的就是想询问下要存对象的哪些属性
读取方法(解档):
调用NSKeyedArchiver的unarchiverObjectWithFile:方法,执行enachiverObjectWithFile:方法时就会调用initWithCoder:方法,
调用initWithCoder:方法目的就是询问下要读的对象有那些属性要读,怎么读。
当有继承关系时,必须调用父类的归档解档方法,当有组合包含关系时,也必须实现所包含对象类的归档解档方法。
8、为什么很多内置类如UITableViewController的delegate属性都是weak而不是strong?
会引起循环引用的问题。
UITableViewController内部有一个强指针tableView属性,
tableView指针指向一个UITableView,UITableView内部有一个强指针subviews属性,
指向一个装着UITableView全部的子控件的强指针数组,数组中又有强指针指向UITableView中存在的子控件。
tableView内部有一个指针delegate,tableView的delegate就是控制器本身,二者相互引用,
如果delegate属性是strong就会引起循环应用,造成内存泄露,因此必须有一个对象是弱指针,所以delegate是weak。
9、UI控件为什么不用strong用weak?
控制器有个强指针View属性,View属性指向内存中的一个UIView,UIView内部有一个强指针subviews属性,
指向一个装着UIView全部的子控件的强指针数组,数组中又有强指针指向UIView中存在的子控件。
所以,只要控制器在,View就在,View中的子控件就在,所以,ui控件没必要用强指针,用weak就可以。
10、block使用时的注意点?
Block可以使用在定义之前声明的局部变量。
int i = 10;
void(^myBlock)() = ^;
myBlock();
在定义Block时,会在Block中建立当前局部变量内容的副本(拷贝)。
后续再对该变量的数值进行修改,不会影响Block中的数值。
以上代码输出结果为10。
如果需要在block中保持局部变量的数值变化,需要使用__block关键字。使用__block关键字后,同样可以在Block中修改该变量的数值。
将第一行代码改为: __block int i = 10;后,输出结果就变成了100;
另外:block代码块中不能直接用点语法调用self的方法,会造成循环引用,要用中括号调用。
11、如何对UITableView进行优化?
UITableViewCell的重用原理:
当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,等待重用。
当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,如果池中有未使用的UITableViewCell,
dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象。
还有一个非常重要的问题:有时候需要自定义UITableViewCell(用一个子类继承UITableViewCell),
而且每一行用的不一定是同一种UITableViewCell(如短信聊天布局),所以一个UITableView可能拥有不同类型的UITableViewCell,
对象池中也会有很多不同类型的UITableViewCell,时可能会得到错误类型的UITableViewCell那么UITableView在重用UITableViewCell。
解决方案:UITableViewCell有个NSString *reuseIdentifier属性,可以在初始化UITableViewCell的时候传入一个特定的字符串标识来设置reuseIdentifier(一般用UITableViewCell的类名)。
当UITableView要求dataSource返回UITableViewCell时,
先通过一个字符串标识到对象池中查找对应类型的UITableViewCell对象,
如果有,就重用,如果没有,就传入这个字符串标识来初始化一个UITableViewCell对象。
12、UIView动画与核心动画的区别?
UIView动画与核心动画的区别:
1、核心动画只作用在CALayer上面,UIView是没有办法使用核心动画的
2、核心动画看到的都是假象,并没有修改UIView的真实位置
什么时候使用UIView动画?
需要与用户进行交互的时候使用UIView动画,如果不需要与用户进行交互,两者都可以使用。
什么时候使用核心动画?
1、根据路径做动画,要使用核心动画(帧动画)
2、做转场动画时,也要使用核心动画
13、自定义视图中重写layoutsubView需要调用父类的layoutsubView吗,为什么?
如果重写的控件是UIView不调用父类的layoutsubView也没关系,里面没有任何子控件,所以不会做什么事情。一般系统自带视图中有子控件的都会重写layoutSubviews方法,因此我们自定义系统自带控件并且重写layoutSubviews必须调用[super layoutSubviews],先布局系统自带子控件的位置和尺寸,才设置我们自己的控件位置和尺寸。否则会发现想用系统自带视图的子控件的时候,会出现意想不到的效果。
14、应用程序的启动流程?
1.执行Main
2.执行UIApplicationMain函数.
3.创建UIApplication对象,并设置UIApplicationMain对象的代理.
UIApplication的第三个参数就是UIApplication的名称,如果指定为nil,它会默认为UIApplication.
UIApplication的第四个参数为UIApplication的代理.
4.开启一个主运行循环.保证应用程序不退出.
5.加载info.plist.加载配置文件.判断一下info.plist文件当中有没有Main storyboard file base name里面有没有指定storyboard文件,如果有就去加载info.plist文件,如果没有,那么应用程序加载完毕.
15、NSString 的时候用copy和strong的区别?
OC中NSString为不可变字符串的时候,用copy和strong都是只分配一次内存,但是如果用copy的时候,需要先判断字符串是否是不可变字符串,如果是不可变字符串,就不再分配空间,如果是可变字符串才分配空间。如果程序中用到NSString的地方特别多,每一次都要先进行判断就会耗费性能,影响用户体验,用strong就不会再进行判断,所以,不可变字符串可以直接用strong。
16、事件传递与响应的完整过程?
在产生一个事件时,系统会将该事件加入到一个由UIApplication管理的事件队列中,
UIApplication会从事件队列中取出最前面的事件,将它传递给先发送事件给应用程序的主窗口.
主窗口会调用hitTest方法寻找最适合的视图控件,找到后就会调用视图控件的touches方法来做具体的事情.
当调用touches方法,它的默认做法, 就会将事件顺着响应者链条往上传递,
传递给上一个响应者,接着就会调用上一个响应者的touches方法
17.ASIHttpRequest、AFNetWorking之间的区别?
- ASIHttpRequest功能强大,主要是在MRC下实现的,是对系统CFNetwork API进行了封装,支持HTTP协议的CFHTTP,配置比较复杂,并且ASIHttpRequest框架默认不会帮你监听网络改变,如果需要让ASIHttpRequest帮你监听网络状态改变,并且手动开始这个功能。
- AFNetWorking构建于NSURLConnection、NSOperation以及其他熟悉的Foundation技术之上。拥有良好的架构,丰富的API及模块构建方式,使用起来非常轻松。它基于NSOperation封装的,AFURLConnectionOperation子类。
- ASIHttpRequest是直接操作对象ASIHttpRequest是一个实现了NSCoding协议的NSOperation子类;AFNetWorking直接操作对象的AFHttpClient,是一个实现NSCoding和NSCopying协议的NSObject子类。
- 同步请求:ASIHttpRequest直接通过调用一个startSynchronous方法;AFNetWorking默认没有封装同步请求,如果开发者需要使用同步请求,则需要重写getPath:paraments:success:failures方法,对于AFHttpRequestOperation进行同步处理。
- 性能对比:AFNetworking请求优于ASIHttpRequest;
18.如何进行真机调试?
1.首先需要用钥匙串创建一个钥匙(key);
2.将钥匙串上传到官网,获取iOS Development证书;
3.创建App ID即我们应用程序中的Boundle ID;
4.添加Device ID即UDID;
5.通过勾选前面所创建的证书:App ID、Device ID;
6.生成mobileprovision文件;
7.先决条件:申请开发者账号 99美刀
19.APP发布的上架流程?
1.登录应用发布网站添加应用信息;
2.下载安装发布证书;
3.选择发布证书,使用Archive编译发布包,用Xcode将代码(发布包)上传到服务器;
4.等待审核通过;
5.生成IPA:菜单栏-&Product-&Archive.
20.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
- 不能向编译后得到的类中增加实例变量;
- 能向运行时创建的类中添加实例变量;
解释如下:
因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表 和 instance_size 实例变量的内存大小已经确定,同时runtime 会调用 class_setIvarLayout 或 class_setWeakIvarLayout 来处理 strong weak 引用。所以不能向存在的类中添加实例变量;
运行时创建的类是可以添加实例变量,调用 class_addIvar 函数。但是得在调用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上。
21.以+ scheduledTimerWithTimeInterval…的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?
RunLoop只能运行在一种mode下,如果要换mode,当前的loop也需要停下重启成新的。利用这个机制,ScrollView滚动过程中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode会切换到UITrackingRunLoopMode来保证ScrollView的流畅滑动:只能在NSDefaultRunLoopMode模式下处理的事件会影响ScrollView的滑动。
如果我们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。
同时因为mode还是可定制的,所以:
Timer计时会被scrollView的滑动影响的问题可以通过将timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)来解决。代码如下:
[NSTimer scheduledTimerWithTimeInterval: target: selector:@selector(timerTick:) userInfo: repeats:];
NSTimer *timer = [NSTimer timerWithTimeInterval: target: selector:@selector(timerTick:) userInfo: repeats:];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
22.runloop和线程有什么关系?
总的说来,Run loop,正如其名,loop表示某种循环,和run放在一起就表示一直在运行着的循环。实际上,run loop和线程是紧密相连的,可以这样说run loop是为了线程而生,没有线程,它就没有存在的必要。Run loops是线程的基础架构部分, Cocoa 和 CoreFundation 都提供了 run loop 对象方便配置和管理线程的 run loop (以下都以 Cocoa 为例)。每个线程,包括程序的主线程( main thread )都有与之相应的 run loop 对象。
runloop 和线程的关系:
- 主线程的run loop默认是启动的。
iOS的应用程序里面,程序启动后会有一个如下的main()函数
* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, , NSStringFromClass([AppDelegate class]))
重点是UIApplicationMain()函数,这个方法会为main thread设置一个NSRunLoop对象,这就解释了:为什么我们的应用可以在无人操作的时候休息,需要让它干活的时候又能立马响应。
- 对其它线程来说,run loop默认是没有启动的,如果你需要更多的线程交互则可以手动配置和启动,如果线程只是去执行一个长时间的已确定的任务则不需要。
- 在任何一个 Cocoa 程序的线程中,都可以通过以下代码来获取到当前线程的 run loop 。
NSRunLoop *runloop = [NSRunLoop currentRunLoop]
23.如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
dispatch_group_async(group, queue, ^{
dispatch_group_async(group, queue, ^{
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
24.HTTP协议的特点,关于HTTP请求GET和POST的区别?
HTTP协议的特点:
- HTTP超文本传输协议,是短连接,是客户端主动发送请求,服务器做出响应,服务器响应之后,链接断开。HTTP是一个属于应用层面向对象的协议,HTTP有两类报文:请求报文和响应报文。
- HTTP请求报文:一个HTTP请求报文由请求行、请求头部、空行和请求数据4部分组成。
- HTTP响应报文:由三部分组成:状态行、消息报头、响应正文。
GET和POST的区别:
- GET请求:参数在地址后拼接,没有请求数据,不安全(因为所有参数都拼接在地址后面),不适合传输大量数据(长度有限制,为1024个字节)。
GET提交、请求的数据会附在URL之后,即把数据放置在HTTP协议头中。以?分割URL和传输数据,多个参数用&连接。如果数据是英文字母或数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。
- POST请求:参数在请求数据区放着,相对GET请求更安全,并且数据大小没有限制。把提交的数据放置在HTTP包的包体中.
- GET提交的数据会在地址栏显示出来,而POST提交,地址栏不会改变。
传输数据的大小:
- GET提交时,传输数据就会受到URL长度限制,POST由于不是通过URL传值,理论上书不受限。
- POST的安全性要比GET的安全性高;
- 通过GET提交数据,用户名和密码将明文出现在URL上,比如登陆界面有可能被浏览器缓存。
25.如何理解MVC设计模式?
MVC是一种架构模式,M表示MOdel,V表示视图View,C表示控制器Controller:
- Model负责存储、定义、操作数据;
- View用来展示书给用户,和用户进行操作交互;
- Controller是Model和View的协调者,Controller把Model中的数据拿过来给View用。Controller可以直接与Model和View进行通信,而View不能和Controller直接通信。View与Controller通信需要利用代理协议的方式,当有数据更新时,Model也要与Controller进行通信,这个时候就要用Notification和KVO,这个方式就像一个广播一样,MOdel发信号,Controller设置监听接受信号,当有数据更新时就发信号给Controller,Model和View不能直接进行通信,这样会违背MVC设计模式。
26.线程与进程的区别和联系?
- 一个程序至少要有进城,一个进程至少要有一个线程。
- 进程:资源分配的最小独立单元,进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
- 线程:进程下的一个分支,是进程的实体,是CPU调度和分派的基本单元,它是比进程更小的能独立运行的基本单位,线程自己基本不拥有系统资源,只拥有一点在运行中必不可少的资源(程序计数器、一组寄存器、栈),但是它可与同属一个进程的其他线程共享进程所拥有的全部资源。
- 进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。
- 进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。
- 但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:39236次
积分:1736
积分:1736
排名:千里之外
原创:134篇
转载:23篇
(13)(10)(9)(15)(1)(13)(4)(4)(12)(10)(40)(7)(15)(7)

我要回帖

更多关于 魅蓝6计步器在哪里 的文章

 

随机推荐