蓝懿iOS 技术内容和心得 16.1.15

本文详细介绍了iOS开发中的预处理指令,包括不带参数和带参数的宏定义,以及宏定义的使用注意事项。文章通过实例演示了宏定义在计算圆周率、求平均值等问题中的应用,对比了宏定义与函数的区别,强调了宏定义在编译阶段进行文本替换的特性及其可能带来的问题,如语法检查缺失和计算顺序不当等。
摘要由CSDN通过智能技术生成

  今天和大家分享一些零碎的知识点

1.关联

objc_setAssociatedObject关联是指把两个对象相互关联起来,使得其中的一个对象作为另外一个对象的一部分。

2.tableView的beginUpdates 和 endUpdates

3.关于代码与storyBoard的自动布局

4.国际化与本地化,为了实现全球化

5.技巧

可以通过设置Scheme来设置app所运行的语言,你想要什么语言就是什么语言,而不用重新设置系统的语言。

6.ios8新特性,加载js

如果我想要加载一个形如网页的东西,那么我需要对整个网页进行动态的编辑,图文混编,但是这样做那面会带来很困难的操作,其实服务端那边很好的可以解决这个问题,用一个网页即可以搞定。服务端那边只需返回一个html文档,然后客户端根据这个html文档进行解析即可。

WKWebView新特性:

在性能、稳定性、功能方面有很大提升(最直观的体现就是加载网页是占用的内存,模拟器加载百度与开源中国网站时,WKWebView占用23M,而UIWebView占用85M);

允许JavaScript的Nitro库加载并使用(UIWebView中限制);

支持了更多的HTML5特性;

高达60fps的滚动刷新率以及内置手势;

将UIWebViewDelegate与UIWebView重构成了14类与3个协议

7.技巧

写函数的时候一定要判断数据的安全性,这样出错的几率就会很小,尤其是要判断它的类型安全,是否为空等,不然程序会奔溃。还有需要注意的地方就是,写每一个函数的时候要多方面进行考虑,考虑代码的合法性。使用前不判断参数的正确性,在函数内部对参数的可靠性进行判断。如果这样的话,你用到函数的时候都需要对这些参数进行判断其合法性如果放倒函数中那么只需要判断一次就可以了。

8.应用内购买

9.sqlite

利用sqlite创建索引,索引是关系数据库中用于存放每一条记录的一种对象,主要目的是加快数据的读取速度和完整性检查。索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。

10.数据库版本的更新,当应用数据表需要添加新表的时候,需要对数据插入新的字段,那么久需要更新数据库

11.友盟统计

当应用上线后可以观察到应用的日志文件,crash日志,页面记时日志,收集并归类崩溃日志,提供错误管理及分析工具,帮助开发者更好的解决问题,从而提高应用的稳定性,改善应用质量。

12.可以获取手机上的语言?你知道吗

13.使用js的时候需要使用webView

1

[webView stringByEvaluatingJavaScriptFromString:scriptString];

14.做常用设备登陆的策略可以使用服务器,服务器把所有登陆过的设备都存储下来。

15.涉及到系统偏好设置的选项,把它都放到一个文件中,这样修改起来比较容易。

16.利用VVDocumenter-Xcode

自动生成注释,也就是xcode的插件.运行VVDOcumenter-Xcode编译后,重新打开xcode即可以使用了

17.如何使用xib进行界面的搭建

利用file’s owner进行关联,形如storyBoard中的segue

18.如何在一个项目中使用多个storyBoard

19.如何利用代码与storyBoard或者XIB进行自动布局

20、XIB进行国际化

首先在工程中需要添加你想要使用的语言,然后新建视图的时候选择使用XIB,这样xcode就会自动为你新建一个xib文件,然后在inspector中的localization中选择localized,开始时一定要选择base,然后勾选其他语言,这样你发现XIB文件会有子目录,然后在子目录下你可以设置不同的语言翻译。

21.tableView小技巧

根据设置不同的identifier取出不同类型的cell,在设置identifier的时候可以设置成类名,这样的话就可以省很多事,而且很方便。

22. 技巧

1

[[UIApplication sharedApplication]setStatusBarHidden:YES];

23.版本控制

gitLab和sourceTree结合使用对源代码进行管理,如何进行相关的配置

24.发送语音消息

三方库opencore-amr

25.Sqlcipher+FMDB,数据库文件加密

https://www.zetetic.net/sqlcipher/ios-tutorial/

26.技巧

图片浏览XHImageViewer

28.技巧

根据button的不同状态可以设置button的事件,相当于微信发送语音信息的按钮,按住录音,松开结束录音并发送消息,

29.技巧

把block指针变量设置成私有的,这样是不是很好用。

30.功能说明

1

[NSObject cancelPreviousPerformRequestsWithTarget:selfselector:@selector(overtimeRemind)object:nil];

先看这段代码:

1

2

3

4

5

-(void)viewDidAppear:(BOOL)animated{

    [superviewDidAppear:animated];

    [NSObject cancelPreviousPerformRequestsWithTarget:selfselector:@selector(showLeft)object:nil];

    [selfperformSelector:@selector(showLeft)];

}

为什么[self performSelector:@selector(showLeft)];前面还需要调用cancelPreviousPerformRequestsWithTarget:self方法呢?

那是因为有时候我们通过[self performSelector:@selector(showLeft)];来实现showLeft方法,可能会出现延迟执行或内存泄漏的问题,而前面加上这句话:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showLeft) object:nil];

可以先将这在执行的方法取消,在继续执行,有效避免了上述两个问题。

31.runLoop

关于runloop的一些了解,runloop是一种运行池,是和多线程有关的东西,监听事件的产生,如果有新事件,那么runloop会监听,一旦监听到了,就会执行监听到的方法。

32.技巧

关于用户头像的问题,点击放大,等其他手势的库ESImageViewController

33.技巧

1

NSString*pullSuccessIdString=[pullSuccessMsgIds componentsJoinedByString:@","];

把数组中的每个元素用逗号拼接成一个字符串

34.数据共享

Multipeer Connectivity Framework ,近距离通信,双方建立连接后可以彼此进行通信

35.问题

oc中不支持多继承,也就说一个类只能继承至一个类,不能继承多个类。实现多继承可以使用协议来实现,也就说某个类中可以继承多个协议,这久相当于多继承,我可以拥有很多协议并且实现它。

36.multipeerConnectivity的实现,对文件进行共享

37.indexPathForSelectedRow

38.如何给另一台电脑进行真机调试

《1》导出p12文件

《2》导出描述文件

《3》在另一台电脑上双击即可以安装了

39.问题

1

[[NSBundle mainBundle]pathForResource:@"quickLookWord"ofType:@"docx];

找不到文件目录,[NSBundle mainBundle]其获取的路径是你程序的安装路径下的资源文件位置。 在xcode中采用add file to 方式添加文件时,一般情况下xcode会自动将文件添加到你的资源文件,而且,这些文件在你工程的 build Phases中的 copy Bundle Resources中可以查看到。但是有时候,由于xcode的问题,采用add files to 不能自动添加到你的资源文件中,这时,可以采用copy Bundle Resources下面的“+”号,手动将文件添加到你的资源文件中,这样就可以解决问题了。

40.功能实现

实现文件的一些操作,包括文件的近距离通信,MC,AirDrop,文件预览

41.Uniform Type Identifiers (UTIs)统一标示符(UTIs)

当你把图片分享之其他iOS设备,接收方会自动打开拍照类app并加载图片。如果你传递的是PDF文件,接收方设备可能会提示你选择一个app来打开文件,或者直接在iBooks中打开。iOS是如何知道哪个app适合什么样的数据类型呢?

在系统中,苹果用UTIs来处理数据类型的标示。简单的说,一个uti是用来标示特定类型的数据或文件。例如,com.adobe.pdf标示一个pdf文件,而public.png代表一个PNG图片。在这里可以查看已经在系统中注册了的完整的UTIs清单。(love cc cat)应用程序可以打开在iOS系统中已经注册了的UTI。因此无论文件是否被打开,iOS都会用特定的程序打开这个文件。

42.关于info.plist文件的操作

1

2

3

4

5

NSDictionary*infoDictionary=[[NSBundle mainBundle]infoDictionary];

NSString*name=[infoDictionary objectForKey:@"CFBundleName"];

NSString*version=[infoDictionary objectForKey:@"CFBundleVersion"];

43.URL Scheme

是类似http://,ftp://,afp://这样的东西,通常是用传输协议作为URL Scheme。不过事实上,你可以在iOS和Mac中注册任何类型的URL Scheme。当用户在浏览器中访问你的自定义URL Scheme的链接的时候,操作系统就会打开你的程序,响应这个请求。

要在程序中注册自定义URL Scheme非常简单。主要分为两个步骤:在程序的Info.plist中加入你需要注册的URL Scheme,然后在你的应用程序中加入处理这类请求的代码。

其中,第一个步骤对于iOS和Mac应用程序来说是完全相同的。方法如下:

在Info.plist中,增加一个字段,名称为CFBundleURLTypes(URL Types)。Xcode会自动为你创建一个必须的键:URL Identifier(CFBundleURLName),这个键的值可以赋值为一个唯一的字符串。通常是逆向的域名结构,如:me.venj.myapp。然后在URL Types这个键下增加一个子项:CFBundleURLSchemes(URL Schemes),这里填入你想注册的URL Scheme的名称,如:cloud。你可以增加多个URL Scheme。

44.在我的APP中打开其他的App

那怎样来制作从一个应用打开其他应用,这其实很简单,打开info.plist,添加一项URL types,展开URL types,再展开Item1,将Item1下的URL identifier修改为URL Scheme,展开URL Scheme,将Item1的内容修改为myapp其他程序可通过myapp://访问此自定义URL。其实就是类似下面的样式。

https://appsto.re/cn/YSJRZ.i

45.问题

添加约束后,当想改变约束的时候,可以更具约束获得约束的值。比如我设置了高的约束是20,那么我以后想把高的约束改为40,那我咋么办,我需要根据这个约束进行修改。或者我需要根据某个约束获取起约束的值,那么我也需要根据约束来获得它的值。

46.关于自动布局修改约束

如果给一个视图添加了约束,你可以修改约束,来改变之前所添加的约束

ContentHightConstraint.constant = 150; 修改之前的约束

47.用通知中心的缺点别人看代码比较

48.问题

NSTimer不能归档持久化,只有实现了NScode协议的才能持久化,即使是归档也不好使,不知道有没有一种方法可以进行序列化

49.技巧

在iOS7之后我们可以用UIFont的preferredFontForTextStyle:类方法来指定一个样式,并让字体大小符合用户设定的字体大小。通过手机设置app字体的大小。目前可供选择的有六种样式:

50.mac终端命令

vi 文件名

q!强制退出

i编辑模式

esc commend 模式 shift +double click z 保存并推出

cat 文件名,查看文件内容

51.Debug的一些有用的操作

截取屏幕图,debug---》view debugging ——>take screenshot of iPhone

查看view的frame  debug ——> show view frame

52.真正懂得自动布局吗?

自动布局会自动根据约束进行计算view的frame,所以你添加的约束必须保证能正常就算出view的frame,如果不能那么你就需要添加约束,也就是说,你既不能多添加了约束也不能少添加约束,UILAbel如果不添加高度约束,它会自动帮你计算出高度的。总的来说,只要让自动布局知道视图的frame就行。如果不能知道,那么会报错

42.你的视图有比较简单的布局改变

当需要产生动画或动态添加视图时,autolayout就暴露了出我认为让人抓狂的元凶——优先级(Priority)和布局冲突。 autolayout对于相同方位的约束,如都是描述离superview上边缘距离的约束,如果这两个约束的数值不同,但是优先级一样,则 autolayout将报布局冲突,将会根据其计算丢弃某一条约束(这时可能就会丢弃你想要的约束,而恰恰保留了你不想看到的布局)。所以,当我们发生布 局变化时,无法像frame的绝对定位,直接改变,并且只有唯一的位置信息。那么,我们该怎么处理这种布局冲突呢?那就是让描述相同但数值不同的这两个约 束采用不同的优先级。autolayout默认将使用数值较大的优先级约束。?但是当我们新增了一个更高优先级约束改变了视图布局,在完成一些操作后,又想变回去怎么办?这时就必须删除更高优先级的约束。?所以,对于视图有动态变更时,我的通常做法是:为需要变更的控件新增默认constraint,但对于这个默认constraint先降低优先级,在发生 变化时再新增一个更高优先级的constraint2,且代码中用一个Dictionary缓存该constraint2的对象,便于我随时删除或重新新 增,让视图来回变化。

53.AD-hoc 是干什么的

是在把app发布到store上进行测试用的。也就是说我把对方设备好添加进来,我打一个包给对方,对方就可以通过itune安装这个ipa文件,就可以进行真机测试了,不需要通过xcode进行安装了。

54.枚举的定义方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

enum{

     UITableViewCellStyleDefault,

     UITableViewCellStyleValue1,

     UITableViewCellStyleValue2,

     UITableViewCellStyleSubtitle

};

typedefenum{

     UITableViewCellStyleDefault,

     UITableViewCellStyleValue1,

     UITableViewCellStyleValue2,

     UITableViewCellStyleSubtitle

}UITableViewCellStyle;

typedef NS_ENUM(NSInteger,UITableViewCellStyle){

     UITableViewCellStyleDefault,

     UITableViewCellStyleValue1,

     UITableViewCellStyleValue2,

     UITableViewCellStyleSubtitle

};

typedefenum{

     UITableViewCellStyleDefault,

     UITableViewCellStyleValue1,

     UITableViewCellStyleValue2,

     UITableViewCellStyleSubtitle

};

typedef NSInteger UITableViewCellStyle;

55.如果页面上的数据是在服务端,且服务端的信息可能会随时改变。那么我们需要把每次请求数据确保每次的数据是最行的数据。但是每次加载数据是不难免会很影响用户体验,所以我需要本地缓存数据。页面先加载本地数据,然后在进行网络请求加载数据。等网络请求数据成功以后,在把新加载进来的数据更新UI

56.数据库的一些操作

1

2

3

4

5

6

7

sqlite>CREATE TABLE testtable(first_col integerDEFAULT0,second_col varchar DEFAULT'hello');

sqlite>CREATE TABLE testtable(first_col integerUNIQUE);

sqlite>CREATE TABLE testtable(first_col integerCHECK(first_col<5));

sqlite>ALTER TABLE testtable ADD COLUMN second_col integer;

sqlite>CREATE VIEW testview ASSELECT*FROM testtable WHEREfirst_col>100;

sqlite>CREATE TEMP VIEW tempview ASSELECT*FROM testtable WHEREfirst_col>100;

sqlite>DROP VIEW testview;

57.uitextView获取光标的位置

1

intlocation=aTextView.selectedRange.location;


预处理指令简介

1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令

作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通常的编译

2.为了区分预处理指令和一般的C语句,所有预处理指令都以符号"#

"开头,并且结尾不用分号

3.预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,它的作用范围就是整个源程序文件

4.C语言提供的预处理指令主要有:宏定义

文件包含条件编译

 

这一讲先介绍一下宏定义,

宏定义可以分为2种:不带参数的宏定义 和 带参数的宏定义。

回到顶部

一、不带参数的宏定义

1.一般形式

#define

 宏名 字符串 

 比如#define ABC 10

右边的字符串也可以省略,比如#define ABC

 

2.作用

它的作用是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。

接下来写个程序根据圆的半径计算周长

 1

#include <stdio.h> 2 3 // 源程序中所有的宏名PI在编译预处理的时候都会被3.14所代替 4 #define PI 3.14 5 6 // 根据圆的半径计radius算周长 7 float girth(float radius) { 8return 2 * PI *radius; 9 }10 11 int main ()12 {13  float g = girth(2);14  15 printf("周长为:%f", g);16  return 0;17 }

在第4行定义了一个叫PI的宏,在编译预处理之后,第8行中的2 * PI *radius就会变成2 * 3.14 * radius。

输出结果:

 

3.使用习惯与注意

1> 宏名一般用大写字母,以便与变量名区别开来,但用小写也没有语法错误

2> 对程序中

用双引号扩起来的字符串内的字符,不进行宏的替换操作。比如:

1

#define R 102 int main ()3 {4  char *s = "Radio";5  return 0;6 }

在第1行定义了一个叫R的宏,但是第4行中"Radio"里面的'R'并不会被替换成10

3> 在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候才对已经展开宏名的源程序进行语法检查

1

#define I 1002 int main ()3 {4  int i[3] = I;5  return 0;6 }

在做编译预处理的时候,不管语法对不对,第4行的I都会被替换为100。不过在编译的时候就会报第4行的错。

4> 宏名的有

效范围是从定义位置到文件结束。如果需要终止宏定义的作用域,可以用#undef命令

1

#define PI 3.142 /*3 .4 .5 .6 .7 */8 #undef PI

PI这个宏在第1行到第8行之间是有效的,第8行后就无效了

5> 定义一个宏时

可以引用已经定义的宏名

#define

R 3.0#define PI 3.14#define L 2*PI*R#define S PI*R*R

 

回到顶部

二、带参数的宏定义

1.一般形式

#define 宏名(参数列表) 字符串

 

2.作用

在编译预处理时,将源程序中所有宏名替换成字符串,并且将 字符串中的参数 用 宏名右边参数列表 中的参数替换

 1

#include <stdio.h> 2 3 #define average(a, b) (a+b)/2 4 5 int main () 6 { 7  int a = average(104); 8  9 printf("平均值:%d", a);10  return 0;11 }

 第3行中定义了一个带有2个参数的宏average,第7行其实会被替换成:int

 a = (10 + 4)/2;,输出结果为:。是不是感觉这个宏有点像函数呢?

 

3.使用注意

1> 宏名和参数列表之间不能有空格,否则空格后面的所有字符串都作为替换的字符串

1

#define average (a, b) (a+b)/22 3 int main ()4 {5  int a = average(104);6  return 0;7 }

注意第1行的宏定义,宏名average跟(a, b)之间是有空格的,于是,第5行就变成了这样:

int

a = (a, b) (a+b)/2(104);

这个肯定是编译不通过的

2> 

带参数的宏在展开时,只作简单的字符和参数的替换,不进行任何计算操作。所以在定义宏时,一般用一个小括号括住字符串的参数。

下面定义一个宏D(a),作用是返回a的2倍数值:

  • 如果定义宏的时候不用

小括号括住参数

 1

#include <stdio.h> 2 3 #define D(a) 2*a 4 5 int main () 6 { 7  int b = D(3+4); 8  9printf("%d", b);10  return 0;11 }

7行将被替换成int

 b = 2*3+4;,输出结果:

  • 如果定义宏的时候

小括号括住参数,把上面的第3行改成:

#define

D(a) 2*(a)

注意右边的a是有括号

的,第7行将被替换成int b = 2*(3+4);,输出结果:

3> 计算结果最好也用括号括起来

下面定义一个宏P(a),作用是返回a的平方:

  • 如果不用

小括号括住计算结果

 1

#include <stdio.h> 2 3 #define Pow(a) (a) * (a) 4 5 int main(int argc, const char * argv[]) { 6  int b = Pow(10) / Pow(2); 7  8 printf("%d", b); 9  return 0;10 }

注意第3行,没有用小括号扩住计算结果,只是括住了参数而已。第6行代码被替换为:

int

b = (10) * (10) / (2) * (2);

简化之后:int

 b = 10 * (10 / 2) * 2;,最后变量b为:

  • 如果

小括号括住计算结果

将上面的第3行代码

改为:

#define

Pow(a) ( (a) * (a) )

那么第6行被替换为:

int

b = ( (10) * (10) ) / ( (2) * (2) );

简化之后:int

 b = (10 * 10) / (2 * 2);,最后输出结果:。这个才是我们想要的结果。

也就意味着前面的#define average(a, b) (a+b)/2应该写成#define average(a, b) (((a)+(b))/2)

 

5.与函数的区别

从整个使用过程可以发现,带参数的宏定义,在源程序中出现的形式与函数很像。但是两者是有本质区别的:

1> 

宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题

2> 

函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数具有更高的执行效率

  • 学习ios  重要还是要理清楚思路  在做或者看老师代码的时候 自己多想想为什么  不要自己看着就抄       另外还是要推荐一下 蓝懿IOS这个培训机构  和刘国斌老师刘国斌老师还是很有名气的,听朋友说刘老师成立了蓝懿iOS,,老师讲课方式很独特,能够尽量让每个人都能弄明白,有的比较难懂的地方,如果有的地方还是不懂得话,老师会换个其它方法再讲解,这对于我们这些学习iOS的同学是非常好的,多种方式的讲解会理解得更全面,这个必须得给个赞,嘻嘻,还有就是这里的学习环境很好,很安静,可以很安心的学习,安静的环境是学习的基础,小班讲课,每个班20几个学生,学习氛围非常好,每天都学到9点多才离开教室,练习的时间很充裕,而且如果在练习的过程中有什么困难,随时可以向老师求助,不像其它机构,通过视频教学,有的甚至学完之后都看不到讲师本人,问点问题都不方便,这就是蓝懿与其它机构的区别,相信在刘国斌老师的细心指导下,每个蓝懿学员都能找到满意的工作,加油!

                                                                      写博客第九十七天;

                                                                                  QQ:565803433


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值