7、iOS 常见问题

[图片上传中。。。(1)]######1、switch语句case中新建变量报语法错误?

将case x: 中的代码块使用 { } 括起来就行。

2、真机调试的时候报错
  • 缺少对应系统版本的镜像文件
  • 拒绝连接,手机没有信任电脑
3、引入百度地图的时候报语法错误

修改文件后缀名为.mm

4、 EXC_BAD_ACCESS 这个错误

其主要原因是因为程序访问了错误的内存地址,根据其后面的判断,是空地址还是一个已经释放的对象地址,具体情况具体分析

SIGSEGV 访问了没有开辟的内存或是已经释放的内存
SIGPIPE对一个一端已经关闭的socket调用两次write,第二次默认结束进程
SIGABRT程序终止,断言或操作系统内部抛出
4、 product archive 无效,不可选

不要选择模拟器,选择Generic iOS Device 或 真机

5、项目选择不了模拟器

目标编译版本太高 在PROJEC -> General -> DeploymentTarget中修改

6、执行PresentViewController比正常感觉慢

因为当前线程可以休眠了,所以执行下面语句唤醒主线程
[self performSelectorOnMainThread:@selector(dontSleep) withObject:nil waitUntilDone:NO];//空操作,为了唤醒主线程

7、添加布局约束后不能准确获取view的frame

在布局所在的superview调用layoutIfNeeded,然后获取约束view的frame

8、tabview和scrollview的滑动手势冲突
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        CGPoint translation = [(UIPanGestureRecognizer *)gestureRecognizer translationInView:self];
        BOOL res = fabs(translation.x) > fabs(translation.y);
        return res;//判断当下的一瞬间是上下滑动还是左右滑动
    }
    return YES;
}
9、两个视图相应同一个手势

默认情况下,两个gesture recognizers不会同时识别它们的手势,但是你可以实现UIGestureRecognizerDelegate协议中的gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:方法对其进行控制。这个方法在这两个gesture recognizers中的任意一个将block另一个的触摸事件时调用,如果返回YES,则两个gesture recognizers可同时识别,如果返回NO,则并不保证两个gesture recognizers必不能同时识别,因为另外一个gesture recognizer的此方法可能返回YES。也就是说两个gesture recognizers的delegate方法只要任意一个返回YES,则这两个就可以同时识别;只有两个都返回NO的时候,才是互斥的。默认情况下是返回NO。

10、iOS上下黑边

项目中还留着Launch Screen ,删掉Launch Screen.xib

7、iOS 常见问题
image.png

将这个换成Launch Images Source 选择Use Asset Catalog

11、有些程序编译完成后不运行 The file “XMPPDemoA” couldn’t be opened because you don’t have permission to view it.

cmd + shift + k,清除一下缓存就好了

12、让一个view的部分区域相应点击事件

重写 – (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

13、让一个手势同时响应上层View事件,也同时响应下层view事件

tap.cancelsTouchesInView = NO;

14、ButtonTitle水平对齐

btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

15、Button点击事件不响应
  • 可能一:没有打开userInteractionEnabled
  • 可能二: 绑定点击事件的对象已经被释放掉了
16、发送一次通知响应两次
  • 因为监听对象注册了两次,而没有移除,所以同一个地方会相应两次
17、ScrollView设置了contentoffset之后经过显示和消失步骤后,contentoffset又变成了0,0

8、多线程

[图片上传中。。。(1)]* 进程

是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。一个进程可以包含多个线程,但至少有一个线程。进程间的内存资源是相互独立的。多开会消耗资源

  • 线程
    线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
    一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
    多线程
  • 优点:提高程序执行效率,
  • 缺点:逻辑会比较复杂,会死锁
  • 队列

    iOS中队列分为

    • 串行队列
    • 并行队列
//并发队列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT)
//串行队列
dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
注:队列完全使用完了之后要 release掉  dispatch_release(quequ);
  • 任务
    • 同步任务
    • 异步任务
//异步任务
    dispatch_async(quequ_chuanxing, ^{
       your Code;
    });
swift 3.0
     DispatchQueue.global().async {
     }

//同步任务
    dispatch_sync(quequ_chuanxing, ^{
        NSLog(@“异步任务”);
    });
//延时执行
    func function3() {
        let delay = DispatchTime.now() + DispatchTimeInterval.seconds(15)
        DispatchQueue.main.asyncAfter(deadline: delay) {
            self.label?.backgroundColor = UIColor.blue
            print("hhhh")
        }
    }

8、多线程
image.png

任务属性决定了代码是否在新线程中执行,队列决定了任务的执行顺序

串行队列 并行队列
同步任务 顺序执行,阻塞主线程,不开启新线程 顺序执行,阻塞主线程,不开启新线程
异步任务asyns 顺序执行,不阻塞主线程,开启新线程(里面的人都都在另一个非主线程中) 交叉执行,不阻塞新线程,开启新线程(执行任务的每个线程都不一样)

多线程实现方式

NSThread 线程声明周期,程序猿自己管理
GCD c风格
NSOperation 面向对象,控制任务个数


dispatch_barrier_async
void dispatch_barrier_async ( dispatch_queue_t queue, dispatch_block_t block );

一个dispatch barrier 允许在一个并发队列中创建一个同步点。当在并发队列中遇到一个barrier, 他会延迟执行barrier的block,等待所有在barrier之前提交的blocks执行结束。 这时,barrier block自己开始执行。 之后, 队列继续正常的执行操作。
调用这个函数总是在barrier block被提交之后立即返回,不会等到block被执行。当barrier block到并发队列的最前端,他不会立即执行。相反,队列会等到所有当前正在执行的blocks结束执行。到这时,barrier才开始自己执行。所有在barrier block之后提交的blocks会等到barrier block结束之后才执行。
这个在globalqueue中无效,因为系统每次分配的全局队列不一定是同一个队列

线程组
dispatch_group_t serviceGroup = dispatch_group_create();//创建线程队列
dispatch_group_enter(serviceGroup);//当前任务加入队列
dispatch_group_leave(serviceGroup);//当前任务出队列

//当所有任务都出队列之后走的方法
dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
 });
Swift 3.0
let group = DispatchGroup.init()
group.enter()
group.leave()
group.notify(queue: DispatchQueue.main) {
     print("最终结果")
}
互斥线程锁

同一时间,只有一个线程可以访问这个资源

@synchronized(self.failedURLs) {
   isFailedUrl = [self.failedURLs containsObject:url];
}
NSOperationQueue 线程队列
 线程队列是用来存在NSOperation的容器,主要用来管理Operation,一个operation添加到Queue中一般就不再需要start了。
创建
     [[NSOperationQueuealloc]init];
方法
- (void)addOperation:(NSOperation *)op;//添加一个operation到queue中会立马异步执行

- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);//添加一组Operation到queue中,wait意思是是否阻塞当前线程,直到里面的线程执行完

- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);//直接用block创建一个operation,并添加进来

- (void)cancelAllOperations;//取消当前队列所有任务

- (void)waitUntilAllOperationsAreFinished;//阻塞当前线程,知道里面的任务全部完成

属性
      @property (readonly, copy) NSArray<__kindof NSOperation *> *operations;//当前队列中有的operation
      @property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0);//当前队列中Operation的数量
      @property NSInteger maxConcurrentOperationCount;//最大并发数量,默认没有限制
      @property (getter=isSuspended) BOOL suspended;//挂起这个队列,只能挂起还没有被执行,正在执行中的不会被暂停
@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
/*告诉系统你的任务是在做什么操作
      与用户交互的任务,这些任务通常跟UI级别的刷新相关,比如动画,这些任务需要在一瞬间完成
    NSQualityOfServiceUserInitiated
    由用户发起的并且需要立即得到结果的任务,比如滑动scroll view时去加载数据用于后续cell的显示,这些任务通常跟后续的用户交互相关,在几秒或者更短的时间内完成
    NSQualityOfServiceUtility
    一些可能需要花点时间的任务,这些任务不需要马上返回结果,比如下载的任务,这些任务可能花费几秒或者几分钟的时间
    NSQualityOfServiceBackground
    这些任务对用户不可见,比如后台进行备份的操作,这些任务可能需要较长的时间,几分钟甚至几个小时
    NSQualityOfServiceDefault
    优先级介于user-initiated 和 utility,当没有 QoS信息时默认使用,开发者不应该使用这个值来设置自己的任务
*/
     @property (nullable, assign /* actually retain */) dispatch_queue_t underlyingQueue//当前queue的gcdqueue
          @property (class, readonly, strong, nullable) NSOperationQueue *currentQueue NS_AVAILABLE(10_6, 4_0);//类属性,用来与其他线程间通信
     @property (class, readonly, strong) NSOperationQueue *mainQueue NS_AVAILABLE(10_6, 4_0);//类属性,用来与其他线程间通信
NSOperation
 相当于虚类,调用start执行main方法,直接用的话啥也不干,如果使用子类的话,最好把操作写在main方法中,一般operation不加到队列里的话是在主线程执行,如果加入队列会新开线程。
 子类使用的话方法写在main中,不要写在start中,不然其他状态不会自动维护。
     - (void)start;//开始方法
     - (void)main;//开始之后执行的方法

     //取消方法与判断,当operation已经在执行中时是cancel不了的,但是会改变iscacelled的值,所以在main方法中(如sdwebimage中),才会在很多地方手动判断是否cancel,然后退出线程执行
     @property (readonly, getter=isCancelled) BOOL cancelled;
     - (void)cancel;
    //是否正在执行
@property (readonly, getter=isExecuting) BOOL executing;
//是否执行完了
@property (readonly, getter=isFinished) BOOL finished;
//是否异步,但是异步却显示0,其实默认是同步,但是加到队列,以及再加一个block会异步
@property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below
@property (readonly, getter=isAsynchronous) BOOL asynchronous
NS_AVAILABLE(10_8, 7_0);
//是否准备好了
@property (readonly, getter=isReady) BOOL ready;
//添加依赖,移除依赖,添加了的话就op进行完了才进行自己
- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;
@property (readonly, copy) NSArray<NSOperation *> *dependencies;
//队列优先级
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
};
@property NSOperationQueuePriority queuePriority;
//执行完成之后调用的block
@property (nullable, copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0);
//阻塞当前线程
- (void)waitUntilFinished NS_AVAILABLE(10_6, 4_0);
//线程优先级 0 - 1
@property double threadPriority NS_DEPRECATED(10_6, 10_10, 4_0, 8_0);
//告诉系统这个线程用来干嘛
@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
//名字
@property (nullable, copy) NSString *name NS_AVAILABLE(10_10, 8_0);
NSBlockOperation
+ (instancetype)blockOperationWithBlock:(void (^)(void))block;//初始化方法
 - (void)addExecutionBlock:(void (^)(void))block;//添加block会异步新开一个线程
 @property (readonly, copy) NSArray<void (^)(void)> *executionBlocks;//已经添加了的block。
NSInvocationOperation
   //初始化方法
 - (nullableinstancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullableid)arg;
 - (instancetype)initWithInvocation:(NSInvocation *)inv NS_DESIGNATED_INITIALIZER;

 @property (readonly, retain) NSInvocation *invocation;
 //返回值?
 @property (nullable, readonly, retain) id result;

两个其实相当于已经封装好了的Operation

-原文链接-