iOS开发遇到的奇葩事

作者: Abson在简书 | 来源:发表于2017-08-23 11:42 被阅读436次
    1、UITextField 和 UITextView 在 iOS7 下不能重写 dealloc 方法

    在 iOS7 的情况下,如果在 Category 重写了 UITextField 或 UITextView 就会发生莫名其妙的崩溃问题。
    得到崩溃的调用栈如下:

    可以看出,系统发出了一个通知,NSNotification,然后 Runloop 往 Observer 发送回调,然后 UITextSelectionView 执行 textSelectionViewActivated 的时候崩溃了。

    很明显在 iOS7 的情况下,iOS 系统默认会在 UITextField 和 UITextView 的 dealloc 方法下去释放一些通知方法,减少 Observer。所以上面我重写了 dealloc 方法,在 iOS7 下不会去释放通知,导致 Runloop 发送了 通知方法的时候找不到对象,从而野指针崩溃。


    iOS系统使用第三方键盘收到三次 UIKeyboardWillShowNotification 通知

    使用搜狗键盘,确实引起了不必要的麻烦,哎,但是 UIKeyboardWillHideNotification 却只会出现一次,Lucky。
    解决方法:

     NSDictionary* dict = [aNotification userInfo];
        CGRect endKeyboardFrame = [[dict objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
        CGRect beginKeyboardFrame = [[dict objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    
        /**
         abson issu1: iOS使用第三方键盘的情况下,收到三次键盘通知,傻B iOS 系统
         */
        if (isShowKeyBoard ) {
            if (false == (fitBeginKeyBoardFrame.size.height > 0 && fitBeginKeyBoardFrame.origin.y - fitEndKeyBoardFrame.origin.y)) {
                return;
            }
        }
    

    iOS7的情况下,如果键盘还在显示的时候,旋转屏幕,系统会分别很快的发出 UIKeyboardWillHideNotification、UIKeyboardWillShowNotification 这两个通知。

    使用键盘的时候注意旋转屏幕出现的这个恶心bug,如果不少心在 UIKeyboardWillHideNotification 的时候做动画,并在动画结束时执行某些动做,例如如下:

    那么就会有一个问题,因为系统很快就发出了 UIKeyboardWillShowNotification 这个通知,但是上图的 manageViewPositionForKeyBoard:这个方法却被 0.25秒后执行了,而界面却没有发生变化,从而导致数据错乱的问题。

    解决方法:加上一个属性判断动画是否执行中,如果 UIKeyboardWillShowNotification 引发的动画在执行中,那么,即使 0.25 秒后也不能让他执行 completion:这个 block。


    iOS7 下两次录音会导致 record 方法返回 false
    _audioRecorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSettings error:&error];
    _audioRecorder.delegate = self;
            
    if ([_audioRecorder prepareToRecord] == YES){
        sleep(0);
        BOOL result = [_audioRecorder record];
        _isRecording = result;
    }
    

    如果上面代码不添加 sleep(0), 就会导致 iOS7 [_audioRecorder record] 第二次创建的时候返回false。

    sleep(0) 的作用:
    Sleep(n)的作用是让当前线程睡眠n毫秒,以便执行其他线程,如果没有其他线程,那睡眠n毫秒后,继续执行。

    而如果n=0,Sleep(0)是指CPU交出当前线程的执行权,让CPU去执行其他线程。也就是放弃当前线程的时间片,转而执行其他线程。

    一般来说,如果当前线程比较耗时比较占CPU资源,可以在结尾处加上Sleep(0), 这样效率会得到大大的提高。

    另外,还可以用这种方法来保证线程同步,线城池工作时,主线程使用Sleep(0)来等待线程池里所有的线程都完成运行。当线程池线程非常多的时候,这种方法确实是一种非常有效的节省 cpu 的方式,因为它节省了在线程里使用内核来进行同步的开销。

    对比上面:
    由于 [_audioRecorder prepareToRecord]为给录音分配资源的api,包括内部线程池分配资源等,所以,加上 Sleep(0) 目的在于等待其线程池资源分配成功。


    iOS 的文件路径保存数据库不可保存全路径
    [[NSUserDefaults standardUserDefaults] setObject:filePath forKey:SocialAudioDataBase];
    

    上面这句话中,如果 filePath 为 /var/mobile/Containers/Data/Application/A07505E5-9A3B-4CF2-B424-738294B1589F/Documents/94538510998/audio/94538510998/3351b914c4c937134c0f57efbc2dcb1b.wav 这样的全路径,下次取出 filePath 的时候,使用

    bool result = [[NSFileManager defaultManager] fileExistsAtPath:audioPath]
    

    result 会返回false。因为每次应用运行的 Application/A07505E5-9A3B-4CF2-B424-738294B1589F 这个路径都在改变。所以保存路径不能保存全路径,只能保存 Documents 文件夹后的部分路径,下次使用的时候,再使用

         NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
            NSString *documentsFilePath = [paths lastObject];
            NSString* fullPath = [documentsFilePath stringByAppendingPathComponent:savePath];
    

    这样去拼接得到全路径路径。


    未完待续....

    相关文章

      网友评论

        本文标题:iOS开发遇到的奇葩事

        本文链接:https://www.haomeiwen.com/subject/sejddxtx.html