iOS开发笔记(七)

正文

这次分享三个有意思的问题:二维码生成、Xcode8单元测试的问题、添加新字体

二维码生成

iOS平台上的二维码生成有很多第三方库,也可以使用原生的方法,这里选用的是QREncoder。 二维码的生成非常简单,仅需几行代码,如下:

    DataMatrix* qrMatrix = [QREncoder encodeWithECLevel:QR_ECLEVEL_H version:QR_VERSION_AUTO string:urlStr];
    int qrcodeImageDimension = 256;
    UIImage* qrcodeImage = [QREncoder renderDataMatrix:qrMatrix imageDimension:qrcodeImageDimension];

但是,在开发的时候,还是会遇到很多的问题:

1、编译失败的问题

编译的时候,会报无法识别class CQR_Encode{...}的错误。 从编译的错误来看,是编译器无法识别C++类CQR_Encode,通过头文件的索引定位到问题: QREncoder 的头文件用到了QR_LEVEL_H 这些属性需要引入QR_Encode.h,QR_Encode.h里面是c++的类; 解决方案有两个,一个是把代码的文件名后缀改成.mm,第二个是修改文件的Type类型为Objective-C++,如下:

这里如果把QR_ECLEVEL_H这几个define改成常量,用extern声明,也是一种解决方案;

2、图片的颜色值异常

QREncoder生成的图片是黑白的,我需要把图片改成下面这样:

设计的同学给出的颜色值是0xFFF04F43,格式是ARGB。 我尝试的解决方案是:遍历像素,把黑色的颜色值改成红色。 在看代码前,介绍几个基本知识点:

  • kCGBitmapByteOrderDefault 是小端模式; RGBA的模式,内存中的布局是0xAABBGGRR ARGB的模式,内存中的布局是0xBBGGRRAA
  • kCGImageAlphaPremultipliedLast 是先把alpha值乘到RGB值,再放到对应的内存;
- (UIImage *)lyRenderBlackToRedColor
{
    // 分配内存
    const int imageWidth = self.size.width;
    const int imageHeight = self.size.height;
    size_t      bytesPerRow = imageWidth * 4;
    uint32_t* rgbImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
    
    // 创建context
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace,
                                                 kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast);
    CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), self.CGImage);
    
    // 遍历像素
    int pixelNum = imageWidth * imageHeight;
    uint32_t* pCurPtr = rgbImageBuf;
    for (int i = 0; i < pixelNum; i++, pCurPtr++)
    {
        // RGBA的模式,内存中的布局是0xAABBGGRR
        // ARGB的模式,内存中的布局是0xBBGGRRAA
        if ((*pCurPtr & 0x00FFFFFF) == 0x00000000 && (*pCurPtr & 0xFF000000) == 0xFF000000)    // 将黑色变成红色
        {
            //            *pCurPtr = 0xFFF04F43;
            uint8_t* ptr = (uint8_t*)pCurPtr;
            ptr[3] = 0xff;
            ptr[2] = 0x43;
            ptr[1] = 0x4f;
            ptr[0] = 0xf0;
        }
        
        
    }
    // 将内存转成image
    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, lyProviderReleaseData);
    CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight, 8, 32, bytesPerRow, colorSpace,
                                        kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast, dataProvider,
                                        NULL, true, kCGRenderingIntentDefault);
    CGDataProviderRelease(dataProvider);
    
    UIImage* resultUIImage = [UIImage imageWithCGImage:imageRef];
    
    // 释放
    CGImageRelease(imageRef);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    
    return resultUIImage;
}

void lyProviderReleaseData (void *info, const void *data, size_t size)
{
    free((void*)data);
}

问题1:CGBitmapContextCreate 创建失败,bitmap的data信息,我发现在上面的代码中仅支持AlphaPremultiplied的类型; 问题2:QREncoder生成的二维码,会有0x00101010 (ARGB)这样的数据,因为alpha=0,0x101010的颜色值会被忽略; 同样的,有部分透明的边会出现0x00ffffff,如果仅仅以RGB的值=0xffffff进行判断,会导致额外的黑边;

Xcode8单元测试的相关问题

1、单元测试的断点失效

stackoverflow上有关于breakpoints in unit test not getting hit的解决方案,但没有解决我的问题,原因可能并不一样。 先尝试非单元测试的raget,可以正常断点; 再尝试其他工程的单元测试,也可以正常断点; 猜测是,单元测试的工程设置存在问题; 仔细查找build setting,找到出问题的设置项:

新建Unit Test的时候,这里的属性值变成了DWARF,没有附带dSYM的符号文件,所以无法断点。

还有其他可能,比如test.m的文件没有加入工程中;(在Build PhasesCompile Soucres可以看到是否添加,也可以通过打Log看是否执行)

2、头文件查找失败

通常是在单元测试中调用了某些第三方库的代码,报.h file not found的错误; 如果单元测试引入文件A,文件A引入了第三方库C,那么需要在build setting添加对应的search framework

如果基础工程的项比较多,可以在选中之后(如上图)按cmd+c 再到新的target的cmd+v

3、embedded错误

错误描述是:ld: embedded dylibs/frameworks are only supported on iOS 8.0 and later (@rpath/XCTest.framework/XCTest) for architecture x86_64 以前加载动态库的时候,记得iOS8.0以上的版本才支持embedded frameworks,新的工程的设置deployment target是7.0。 检查Xcode工程,发现embedded frameworks这一项为空!

Xcode的版本是** Version 8.3.1 (8E1000a)** 猜测是Xcode生成的XCTest Framework是动态库,被Xcodeembedded到项目中。这个版本Xcode能选择最低iOS版本是8.0,所以Xcode可能没有考虑XCTest.framework兼容iOS8以下的情况。 解决方案就是把deployment target暂时设置成8.0。

4、Undefined symbols for architecture x86_64

注意这里的描述是Undefined symbols,表示编译器找到变量的声明,但是没有找到变量的实现,于是在linking的阶段就会报错; 还有一种情况是Use of undeclared identifier,这种是找不到变量的声明,一般是没有引入头文件,或者没有正确设置头文件的search路径。

i386是32位模拟器(5和5s以下的机型) x86_64是64位模拟器(5s后面的机型) armv7/armv7s是32位真机 arm64是64位真机 coocachina上有更详细的介绍。

添加新字体

  • 1、把.ttf字体文件导入Xcode工程;
  • 2、在plist添加对应的字体文件,如下:

plist

  • 3、在代码中通过[UIFont fontWithName:@“newFontName” size:18]加载新字体; newFontName 是字体的名字,通过在Finder双击字体文件,红色圈起来的部分就是字体的family Name,再通过UIFont的-fontNamesForFamilyName方法找到字体名。

字体文件

总结

学而不思则罔,思而不学则殆。 遇到问题,尝试去解决它,并从中得到知识; 思考问题的前因后果,避免再次遇到同样的问题。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术博客

Knockout.Js官网学习(简介)

最近一段时间在网上经常看到关于Knockout.js文章,于是自己就到官网看了下,不过是英文的,自己果断搞不来,借用google翻译了一下。然后刚刚发现在建立a...

14220
来自专栏落影的专栏

iOS开发笔记(二)

前言 开发做笔记是好习惯,总结分享是巩固记忆。 遇到问题,思考其背后的原因、原理。 AFNetworking 1、progress回调block,不在主线程;...

35470
来自专栏iOS122-移动混合开发研究院

PureLayout,使用纯代码写AutoLayout

? ? ? ? ? ? 为iOS和OS X的自动布局最终的API -- 令人印象深刻的简单,非常强大。 PureLayout延伸的UIView /NSView...

33270
来自专栏用户3030674的专栏

Android 性能优化——之图片的优化

 在Android性能优化中,我们会发现占内存最大的和对性能影响最大的往往是图片资源,其次是控件资源。相对来说,其他的资源的影响会小一点。这里我就先对图片资源的...

9810
来自专栏calvin

Quill编辑器介绍及扩展

从这里进入官网. 能找到这个NB的编辑器是因为公司项目需要一个可视化的cms编辑器,类似微信公众号编辑文章。可以插入各种卡片,模块,问题,图片等等。然后插入的内...

69520
来自专栏Kiba518

【我们一起写框架】MVVM的WPF框架之绑定(二)

上一篇我们已经一起编写了框架的基础结构,并且实现了ViewModel反向控制Xaml窗体。

17320
来自专栏me的随笔

H5实现本地预览图片

最后注意一点,H5实现图片预览只能使用原生JS进行DOM元素的操作,若使用jQuery则无法实现该效果。

59020
来自专栏张戈的专栏

根据IE版本加载不同CSS样式的方法小结,解决低版本IE兼容问题

自从中国联盟成员导航采用响应式布局之后,不少朋友反馈该页面在 IE8、IE7 浏览器会错排,经测试发现确实存在这个问题,但我一直也没去深究解决。这几天博客折腾得...

45080
来自专栏ShaoYL

UINavigationController

38260
来自专栏Vamei实验室

Python应用03 使用PyQT制作视频播放器

作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁任何形式转载。

14220

扫码关注云+社区

领取腾讯云代金券