寒哥管理的技术专题程序员iOS Developer

iOS开发遇到的奇葩事

2017-08-23  本文已影响436人  Abson在简书
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];

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


未完待续....

上一篇下一篇

猜你喜欢

热点阅读