iOS 开发问与答(160-173)

160. pod install 警告GCC_PRECOMPILE_PREFIX_HEADER 设置被覆盖

当 pod install 时,出现警告:

[!] The `Client [Debug]` target overrides the `GCC_PRECOMPILE_PREFIX_HEADER` build setting defined in `Pods/Target Support Files/Pods-Client/Pods-Client.debug.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.

意思是主工程 target 中的 GCC_PRECOMPILE_PREFIX_HEADER 设置和 Pods target 中的设置不一样,导致后者会被前者覆盖。解决办法很简单,找到主工程 target build settings 中的 Precompile Prefix Header 一项,点击下拉按钮,选择 other,然后输入 $(inherited) 回车。然后重新 pod install(可能需要关闭 Xcode)。

回到目录

161. 在中文输入法下,如何准确判断 textfield 中字数是否超长?

因为中文输入的情况下,textfield 中输入字母都是暂时的,如果用户选词之后 textfield 中对应的字母还会最终替换成中文。如果你在用户未选词之前计算 textfield 字数是不准确的,因为那不是最终用户想要输入的字符,用户想要输入的字符应该是选定联想词组之后。因此需要在监听方法中进行特殊处理。

首先监听 textfield 的 UIControlEventEditingChanged 方法:

[_textField addTarget:self action:@selector(textFieldChanged:) forControlEvents:UIControlEventEditingChanged];

textFieldChanged: 方法是重点:

- (void)textFieldChanged:(UITextField *)textField {
    NSString *toBeString = textField.text;
    NSArray *currentar = [UITextInputMode activeInputModes];
    UITextInputMode *current = [currentar firstObject];

    if ([current.primaryLanguage isEqualToString:@"zh-Hans"]) { // 简体中文输入,包括简体拼音,健体五笔,简体手写
        UITextRange *selectedRange = [textField markedTextRange];
        //获取高亮部分
        UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
        // 没有高亮选择的字,则对已输入的文字进行字数统计和是否超长判断
        if (!position) {
            if (toBeString.length > charLimited) {
                textField.text = [toBeString substringToIndex:charLimited];
                [self alertForCharLimited];// 超长,弹出 alert 提示
            }
        }
        // 有高亮选择的字符串,则暂不对文字进行统计和限制
    }
    // 中文输入法以外的直接对其统计限制即可,不考虑其他语种情况
    else{
        if (toBeString.length > charLimited) {
            textField.text = [toBeString substringToIndex:charLimited];
            [self alertForCharLimited];// 超长,弹出 alert 提示
        }
    }
    NSLog(@"%@",textField.text);
}

主要原理是在方法中对中文输入法进行判断,如果当前输入法为中文,而且用户有尚未选词的输入,则暂不去判断字数是否超过限制。

回到目录

162. UIImagePickerController 内存泄漏问题

在使用 UIImagePickerController 时,MLeaksFinder 老是报内存泄漏。这是因为在设置 UIImagePickerController 的 delegate 时强引用了 self,导致循环引用,无法释放 UIImagePickerController。

因此,只需要将 delegate 设置为弱引用就好:

__weak __typeof(self)weakSelf=self;
imagePicker.delegate = weakSelf;

回到目录

163. 真机调试报错:dyld: Library not loaded: @rpath/libswiftCore.dylib

模拟器上没问题。这个错误通常可能是以下原因导致的:

  1. 证书问题

    请检查 Apple WWDR 证书和开发者证书是否安装正确。

  2. Xcode 版本冲突问题

    如果你安装了两个版本的 Xcode,比如同时安装了 Xcode 8 和 Xcode 9 beta,则很可能在 Xcode 9 beta 上正常,而 Xcode 8 上不正常了。这时请删除以下文件或文件夹:

    • ~/Library/Developer/Xcode/DerivedData
    • ~/Library/Caches/com.apple.dt.Xcode

回到目录

164. 禁止自动锁屏

在 AppDelegate 中:

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // 禁止自动锁屏
    [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; 
}

回到目录

165. 如何手动安装 iOS 模拟器?

Xcode 8 以后的 iOS 模拟器通过 Prefrences 中的 Components/Simulators 进行管理,但经常出现下载中断无法安装的情况,而且速度非常慢。那么可以用迅雷等工具进行下载后再安装吗?答案是肯定的。

  1. 用 spotlight 打开控制台应用(console)。
  2. 打开 Xcode 9 的 Prefrences/Components/Simulators,选择你想安装的模拟器版本,点击下载,然后取消。
  3. 在 console 中,搜索 dvt,会看到如下记录:DVTDownloadable: Download Cancelled. Downloadable: https://devimages-cdn.apple.com/downloads/xcode/simulators/com.apple.pkg.iPhoneSimulatorSDK10_3-10.3.1.1495751597.dmg.
  4. 将 url 复制粘贴到 迅雷 工具中进行下载。
  5. 下载完成后,将下载到的文件复制到目录:~/Library/Caches/com.apple.dt.Xcode/Downloads
  6. 回到 Xcode,重新下载模拟器版本,这时会发现会跳过 sdk 下载过程直接开始安装。安装完成新版本的模拟器就会在 Schema 菜单中列出。

回到目录

166. 如何手动触发 text field 的文本改变事件?

因为有时候我们会直接修改 text field 的 text 属性,这样如果用监听 UITextFieldTextDidChangeNotification 通知或者 RAC 的 rac_textSignal 的方法都无法监听到此类改变。我们需要在修改 text 之后手动立即触发一个文字改变事件:

self.phoneTextField.text = nil;
// 通知 RAC,文字已改变,否则 RAC 无法监听 text 的改变
[self.phoneTextField sendActionsForControlEvents:UIControlEventEditingChanged];

回到目录

167. 如何在 present 一个控制器时显示半透明遮罩?

PlaylistVC* vc =(PlaylistVC*)[self controllerById:@"PlaylistVC" storyboard:@"play"];

    // 呈现时显示半透明遮罩
    self.definesPresentationContext = YES; //self is presenting view controller
    vc.view.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:.4];
    vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;

    [self presentViewController:vc animated:YES completion:nil];

回到目录

168. 为什么关键帧动画不起作用?

为什么在关键帧动画中,用 addKeyframeWithRelativeStartTime 添加的帧不会以动画方式执行,只会显示最后一帧的结果(中间的帧全部跳过)。

注意参数中的 startTime 和 duration 是否设对。比如下面的代码:

[UIView animateKeyframesWithDuration:duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
    ……
    [UIView addKeyframeWithRelativeStartTime:1/3 relativeDuration:2/3 animations:^{
        snapshot.layer.transform = [self yRotationAngle:0];
      }];
  ……
}];

代码中传递的 startTime 和 duration 使用了整数除法,在 O-C 中整数除法当结果是小数时会自动取整,1/3 和 2/3 取整后结果都是 0,因此所有帧都是从 0% 处开始,执行 0% 的时长,所以动画帧不会以动画方式执行。解决办法很简单,只需将它们修改为 1.0/3 和 2.0/3 即可。

回到目录

169. 如何修改 TextField 的光标颜色?

用代码设置 TextField 的 tintColor,而不要用 IB 设置。

回到目录

170. 为什么替换启动图后不生效?

在 assets 中替换完启动图之后,无论 clean 还是重新安装 app,启动图都还是原来的不会变。要解决这个问题,需要将图片名称修改一下,比如由原来的 LaunchScreen 修改为 LaunchScreen-1。然后在 LaunchScreen.storyboard 中将 image view 的图片名称也换成 LaunchScreen-1。

回到目录

171. 如何查看 mobileprovision 文件中注册的设备数?

mobileprovision 文件是加密的 plist 文件。在终端中输入命令:

security cms -D -i 20180105_hoc_profies.mobileprovision

即可打印出文件内容,其中 key 为 ProvisionedDevices 中包含的是一个字符串数组,数组中列出了所有注册设备的 UUID,将这个数组(即…中的内容)拷贝出来用文本编辑器统计行数即可。

回到目录

172. 为什么自定义 UIView 的 touchesEnded 方法不触发?

一个自定义 UIView 重写了 touchesEnded: 方法,在大部分 UIViewController 中都能响应触摸,但在一个 UIViewController 中使用时就是无法触发 touchesEnded: 方法。后经检查发现,这个 UIViewController 的 view 中添加了一个 UITapGestureRecognizer 手势识别器,把 touchesEnded: 方法给拦截了。只需将这个手势识别器删除,自定义 UIView 就能正确触发 touhesEnded: 方法了。

解决办法,是在自定义 UIView 中改用 touchesBegan: 方法来响应触摸。

回到目录

173. modalPresentationStyle 设置为 UIModalPresentationOverCurrentContext 会有什么效果?

当我们需要 present 一个带半透明遮罩效果的 view controller 时,往往会用:

// 呈现时显示半透明遮罩
    self.definesPresentationContext = YES; //self is presenting view controller
    vc.view.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:.4];
    vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    [self.navigationController setNavigationBarHidden:YES];
    [self presentViewController:vc animated:YES completion:nil];
}

这样做会导致原来的 view controller 的 view 不会从视图树中移除(如果使用默认的 UIModalPresentationFullScreen 的话原来的 view 会从当前视图树中移除),而是作为背景显示在要呈现的 view controller 的 View 下方。这会带来两个附加效果:

  1. 如果原来的 view controller 显示有导航栏,那么导航栏会在 present 之后依然显示。
  2. 原来的 view controller 的 viewWillDisappear/viewDidDisappear 方法不会被调用。

回到目录

猜你喜欢

转载自blog.csdn.net/kmyhy/article/details/80061913