用四舍五入的方法取什么值法取近似值,将数0.256精确到0.01的结果是 ()-|||-A.0.26 B.0.0?


1 西门子 S7-200 PLC
1.为什么要用PC/PPI接口?
因S7-200CPU使用的是RS485,而PC机的COM口采用的是RS232,两者的电气规范并不相容,需要用中间电路进行匹配。PC/PPI其实就是一根RS485/RS232的匹配电缆。
2.晶体管输出与继电器输出各自的优点如何?
晶体管不能带AC220V的交流负载,只能带低压的直流。对抗过载和过压的能力差。但可以高频输出,适合高频率输出的场合,例如脉冲控制。
继电器可以带AC220V和直流的负载。但由于继电器本身的特性决定了它不能高频输出。同时继电器通断的寿命一般在10万次左右。所以在频繁通断的场合也适合用晶体管的。
3.S7-200 CPU上的通讯口,通讯距离究竟有多远?
《S7-200系统手册》上给出的数据是一个网段50m,这是在符合规范的网络条件下,能够保证的通讯距离。凡超出50m的距离,应当加中继器。加一个中继器可以延长通讯网络50米。如果加一对中继器,并且它们之间没有S7-200 CPU站存在(可以有EM277),则中继器之间的距离可以达到1000米。符合上述要求就可以做到非常可靠的通讯。
4.通讯口参数如何设置?
缺省情况下,S7-200 CPU的通讯口处于PPI从站模式,地址为2,通讯速率为9.6K,要更改通讯口的地址或通讯速率,必须在系统块中的通讯端口选项卡中设置,然后将系统块下载到CPU中,新的设置才能起作用。
5.M区域地址不够用怎么办?
有些用户习惯使用M 区作为中间地址,但S7-200CPU中M区地址空间很小,只有32个字节,往往不够用。而S7-200CPU中提供了大量的V 区存储空间,即用户数据空间。V存储区相对很大,其用法与M 区相似,可以按位、字节、字或双字来存取V 区数据。例:V10.1, VB20, VW100, VD200等等。
6.S7-200的远距离通讯有哪些方式?
RS-485网络通讯:PPI、MPI、PROFIBUS-DP协议都可以在RS-485网络上通讯,通过加中继,最远可以达到9600米。
光纤通讯:光纤通讯除了抗干扰、速率高之外,通讯距离远也是一大优点。S7-200产品不直接支持光纤通讯,需要附加光纤转换模块才可以。
电话网:S7-200通过EM241音频调制解调器模块支持电话网通讯。EM241要求通讯的末端为标准的音频电话线,而不论局间的通信方式。通过EM241可以进行全球通讯。
无线通讯:S7-200通过无线电台的通讯距离取决于电台的频率、功率、天线等因素;S7-200通过GSM网络的通讯距离取决于网络服务的范围 ;S7-200通过红外设备的通讯也取决于它们的规格。
7.S7-200支持的通讯协议哪些是公开的,哪些是不公开的?
PPI协议:西门子内部协议,不公开;
MPI协议:西门子内部协议,不公开;
S7协议:西门子内部协议,不公开;
PROFIBUS-DP协议:标准协议,公开 ;
USS协议:西门子传动装置的通用串行通讯协议,公开详情请参考相应传动装置的手册 ;
MODBUS-RTU(从站):公开。
8.S7-200的高速输入、输出如何使用?
S7-200 CPU上的高速输入、输出端子,其接线与普通数字量I/O相同。但高速脉冲输出必须使用直流晶体管输出型的CPU(即DC/DC/DC型)。
9.NPN/PNP输出的旋转编码器(和其他传感器),能否接到S7-200 CPU上?
都可以。S7-200 CPU和扩展模块上的数字量输入可以连接源型或漏型的传感器输出,连接时只要相应地改变公共端子的接法。
10.NPN和PNP传感器混接进S7-200 PLC的方法
大家都知道一般日系PLC如三菱、OMRON等一般公共端是 信号接入的时候通常是选用NPN传感器。欧系PLC的公共端一般是:大多选用PNP的传感器接入信号。如S7-200/300等那么当S7-200 PLC做系统时候,提供的传感器有PNP和NPN两种那么问题怎么解决呢?
方法一:NPN传感器利用中间继电器转接。
方法二:大家在设计的时候一般把200PLC的输入端[M]统一接24V-,其实,200PLC同样可以引入-信号输入,把1M的接24V ,I0.0-0.7统一接NPN传感器,把2M接24V-,把PNP传感器统一接I1.0-1.7这样就能达到NPN&PNP传感器混接进PLC的目的。原因很简单,200PLC支持两种信号接入,内部是双向二极管采用光电隔离进行信号传输的。
11.高速计数器怎样占用输出点?
高速计数器根据被定义的工作模式,按需要占用CPU上的数字量输入点。每一个计数器都按其工作模式占用固定的输入点。在某个模式下没有用到的输入点,仍然可以用作普通输入点;被计数器占用的输入点(如外部复位),在用户程序中仍然访问到。
12.为什么高速计数器不能正常工作?
在程序中要使用初次扫描存储器位SM0.1来调用HDEF指令,而且只能调用一次。如果用SM0.0调用或者第二次执行HDEF指令会引起运行错误,而且不能改变第一次执行HDEF指令时对计数器的设定。
13.高速计数器如何寻址? 为什么从SMDx中读不出当前的计数值?
可以直接用HC0;HC1;HC2;HC3;HC4;HC5对不同的高速计数器进行寻址读取当前值,也可以在状态表中输入上述地址直接监视高速计数器的当前值。SMDx不存储当前值。高速计数器的计数值是一个32位的有符号整数。
14、高速计数器如何复位到0?
选用带外部复位模式的高速计数器,当外部复位输入点信号有效时,高速计数器复位为0, 也可使用内部程序复位,即将高速计数器设定为可更新初始值,并将初始值设为0,执行HSC指令后,高数计数器即复位为0 。
15、为何给高速计数器赋初始值和预置值时不起作用,或效果出乎意料?
高速计数器可以在初始化或者运行中更改设置,如初始值、预置值。其操作步骤应当是:
设置控制字节的更新选项。需要更新哪个设置数据,就把控制字节中相应的控制位置位(设置为“1”);不需要改变的设置,相应的控制位就不能设置;
然后将所需 的值送入初始值和预置值控制寄存器;
执行HSC指令。
2 西门子 S7-300PLC
1.使用CPU 315F和ET 200S时应如何避免出现“通讯故障”消息?
使用CPU S7 315F, ET 200S以及故障安全DI/DO模块,那么您将调用OB35 的故障安全程序。而且,您已经接受所有监控时间的默认设置值,并且愿意接收“通讯故障”消息。OB 35 默认设置为100毫秒。您已经将F I/O模块的F监控时间设定为100毫秒,因此至少每100毫秒要寻址一次I/O模块。但是由于每100毫秒才调用一次OB
35,因此会发生通讯故障。要确保OB35的扫描间隔和F监控时间有所差别,请确保F监控时间大于OB35的扫描间隔时间。
S7分布式安全系统,一直到V5.2 SP1 和 6ES7138-4FA00-0AB0,6 ES7138-4FB00-0AB0,6ES7138-4CF00-0AB0 都会出现这个问题。在新的模块中,F 监控时间设定为150毫秒。
2.当DP从站不可用时,PROFIBUS上S7-300 CPU的监控时间是多少?
使用CPU的PROFIBUS接口上的DP从站操作PROFIBUS网络时,希望在启动期间检查期望的组态与实际的组态是否匹配。在 CPU属性对话框中的Startup选项卡上给出了两个不同的时间。
3.如何判断电源或缓冲区出错,如:电池故障?
如果电源(仅S7-400)或缓冲区中的一个错误触发一个事件,则CPU操作系统访问OB81。错误纠正后,重新访问OB81。电池故障情况下,如果电池检测中的BATT.INDIC开关是激活的,则 S7-400仅访问OB81。如果没有组态OB81,则CPU不会进入操作状态STOP。如果OB81不可用,则当电源出错时,CPU仍保持运行。
4.为S7CPU上的I/O模块(集中式或者分布式的)分配地址时应当注意哪些问题?
请注意,创建的数据区域(如一个双字)不能组态在过程映象的边界上,因为在该数据块中,只有边界下面的区域能够被读入过程映像,因此不可能从过程映像访问数据。因此,这些组态规则不支持这种情况:例如,在一个 256 字节输入的过程映像的 254 号地址上组态一个输入双字。如果一定需要如此选址,则必须相应地调整过程映像的大小(在CPU的Properties中)。
5.在S7 CPU中如何进行全局数据的基本通讯?在通讯时需要注意什么?
全局数据通讯用于交换小容量数据,全局数据(GD)可以是: 输入和输出标记,数据块中的数据,定时器和计数器功能 。
数据交换是指在连入单向或双向GD环的CPU之间以数据包的形式交换数据。GD环由GD环编号来标识。
单向连接:某一CPU可以向多个CPU发送GD数据包。
双向连接:两个CPU之间的连接:每个CPU都可以发送和接收一个GD数据包。
必须确保接收端CPU未确认全局数据的接收。如果想要通过相应通讯块(SFB、FB或FC)来交换数据,则必须进行通讯块之间的连接。通过定义一个连接,可以极大简化通讯块的设计。该定义对所有调用的通讯块都有效且不需要每次都重新定义。
6. 可以将S7-400存储卡用于CPU 318-2DP吗?
在通常的操作中,只能使用订货号为6ES7951-1K... (Flash EPROM)和6ES7951-1A... (RAM)的“短”> 存储卡。
7.尽管LED灯亮,为什么CPU 31xC不能从缺省地址124和125读取完整输入?
对于下列型号的CPU ,请检查 24V 电压是否接入引脚 1。LED由输入电流控制。引脚 1 上的 24V 电压需要做进一步处理。
313C(6ES7 313-5BE0.-0AB0),313C-2DP (6ES7 313-6CE0.-0AB0),313C-2PTP (6ES7 313-6BE0.-0AB0), 314C-2DP (6ES7 314-6CF0.-0AB0),314C-2PTP (6ES7 314-6BF0.-0AB0)
8.配置CPU 31x-2 PN/DP的PN接口时,当PROFINET接口偶尔发生通信错误时,该如何处理?
请确定以太网(PROFINET)中的所有组件(转换)都支持 100 Mbit/s全双工基本操作。避 免中心分配器割裂网络,因为这些设备只能工作于半双工模式。
9.在硬件配置编辑器中,“时钟”修正因子有什么含义呢?
在硬件配置中,通过CPU > Properties > Diagnostics/Clock,你可以进入“时钟”> 域内指定一个修正因子。这个修正因子只影响CPU的硬件时钟。时间中断源自于系统时钟,并且和硬件时钟的设定毫无关系。
10.如何通过PROFIBUS DP用功能块实现在主、从站之间实现双向数据传送?
在主站plc可以通过调用SFC14 “DPRD_DAT“和SFC15 “DPWR_DAT“来完成和从站的数据交换,而对于从站来说可以调用FC1 “DP_SEND“ 和FC2 ”DP_RECV“完成数据的交换。
11.可以从S7 CPU中读出哪些标识数据?
通过SFC 51“RDSYSST”可读出下列标识数据:
可以读出订货号和CPU版本号。为此,使用SFC 51和SSL ID 0111并使用下列索引:
1 = 模块标识;
6 = 基本硬件标识;
7 = 基本固件标识;
12.在含有CPU 317-2PN/DP的S7-300上,如何编程可加载通讯功能块FB14('GET')和FB15('PUT')用于数据交换?
为了通过一个S7连接在使用CPU 317-2PN/DP的两个S7-300工作站之间进行数据交换,其中该S7连接是使用NetPro组态的, 在S7通信中,必须调用通讯功能块。模块FB14('GET') 用于从远程CPU取出数据,模块FB15('PUT')用于将数据写入远程CPU。功能块包含在STEP 7 V5.3的标准库中。< ="" cpu=""
317-2pn/dp的通讯模块fb14('get')和fb15('put')的属性="" :="" ="">
FB14和FB15是异步通讯功能。这些模块的运行可能跨越多个OB1循环。通过输入参数REQ激活FB14或FB15。DONE、NDR或ERROR表明作业结束。PUT和GET可以同时通过连接进行通信。
注意:不能将库SIMATIC_NET_CP中的通讯块用于CPU317-2PN/DP。
13.对于紧凑CPU 313C-2 PtP和CPU 314-2 PtP作业同步处理需要注意什么?
在用户程序中,不可以同时编程SEND作业和FETCH作业。
即:
只要SEND作业(SFB 63)没有完全终止(DONE或ERROR),就不能调用FETCH作业(SFB 64)(甚至在REQ=0的时候);
只要FETCH作业(SFB 64)没有完全终止(DONE或ERROR),就不能调用SEND作业(SFB 63)(甚至在REQ=0的时候);
在处理一个主动作业(SEND作业、SFB 63或FETCH作业、SFB 64)时,同时可以处理一个被动作业(SERVE作业、SFB 65)。
14. 可以将MICR.master420到440作为组态轴(位置外部检测)和CPU 317T一起运行吗?
可以,但在动力和精度方面,对组态轴的要求差别非常大。在高要求情况下,伺服驱动SIMODRIVE 611U、MASTERDRIVES MC或SINAMICS S必须和CPU 317T一起运行。在低要求情况下,MICROMASTER系列也能满足动力和精度要求。
15.如何在已配置为DP从站的两个CPU模块间组态直接数据交换(节点间通信)?
两个CPU站配置为DP从站,而且由同一个DP主站操作,它们之间的通信通过配置交换模式为DX可以完成直接数据交换。
16.如何使用SFC65,SFC66,SFC67 和 SFC68 进行通信?
对于单向基本通信,使用系统功能 SFC67 (X_GET)从一个被动站读取数据,使用系统功能SFC68(X_PUT)将数据写入一个被动站(服务器)。这些块只有在主动站中才调用。对于一个双向基本通信,调用站中的系统功能SFC65 (X_SEND),在该站中想将数据发送到另一个主动站。在同样为主动的主动接收站中,数据将通过系统功能SFC66 (X_RCV)记录。
两种类型的基本通信中,每次块调用可以处理最多 76 字节的用户数据。对于S7-300 CPU,数据传送的数据一致性是 8 个字节,对于S7-400 CPU则是全长。如果连接到S7-200,必须考虑到S7-200只能用作一个被动站。
17.什么是自由分配 I/O 地址?
地址的自由分配意味着您可对每种模块(SM/FM/CP)自由的分配一个地址。地址分配在 STEP 7 里进行。先定义起始地址,该模块的其它地址以它为基准。
自由分配地址的优点:因为模块之间没有地址间隙,就可以优化地使用可用地址空间。在创建标准软件时,分配地址过程中可以不考虑所涉及的 S7-300 的组态。
18.诊断缓冲器能够干什么?
更快地识别故障源,因而提高系统的可用性。评估STOP之前的最后事件,并寻找引起STOP的原因。
诊断缓冲器是一个带有单个诊断条目的循环缓冲器,这些诊断条目显示在事件发生序列中;第一个条目显示的是最近发生的事件。如果缓冲器已满, 最早发生的事件就会被新的条目所覆盖。根据不同的CPU,诊断缓冲器的大小或者固定,或者可以通过HW Config中通过参数进行设置。
19.诊断缓冲器中的条目包括哪些?
1) 故障事件;
2) 操作模式转变以及其它对用户重要的操作事件;
3) 用户定义的诊断事件(用SFC52 WR_USMSG) ;
在操作模式STOP下,在诊断缓冲器中尽量少的存储事件,以便用户能够很容易在缓冲器中找到引起STOP的原因。因此,只有当事件要求用户产生一个响应(如计划系统内存复位,电池需要充电)或必须注册重要信息(如固件更新,站故障)时,才将条目存储在诊断缓冲器中。
20.如何确定MMC的大小以便完整地存储STEP 7项目?
为了给项目选择合适的MMC,需要了解整个项目的大小以及要加载块的大小。可以按照如下所述的方法来确定项目的大小:
1) 首先归档STEP 7项目。然后在Windows资源浏览器中打开已归档项目,并确定其大小(选中该项目并右击)。这会告诉您归档文件的大小。
2) 将块加载入CPU。现在仍然需要选择'PLC > Module Information > Memory'。在此,在' Load memory RAM + EPROM'中,可以看到分配的加载内存的大小。
3) 必须将该值和已经确定的归档项目的大小相加。这样就可以得出在一个MMC上保存整个项目所需的总内存的大小。
21.CPU全面复位后哪些设置会保留下来?
复位CPU时,内存没有被完全删除。整个主内存被完全删除了,但加载内存中数据,以及保存在Flash-EPROM存储卡(MC)或微存储卡(MMC)上的数据,则会全部保留下来。除了加载内存以外,计时器(CPU 312
IFM除外)和诊断缓冲也被保留。具有MPI接口或一个组合MPI/DP接口的CPU只在全部复位之前保留接口所采用的当前地址和波特率。另一方面,另一个PROFIBUS地址也被完全删除,不能再访问。
重要事项:重新设置PG/PC之后,与CPU之间的通讯只能通过MPI或MPI/DP接口来建立。
22.为什么不能通过MPI在线访问CPU?
如果在CPU上已经更改了MPI参数,请检查硬件配置。可以将这些值与在'Set PG/PC interface'下的参数进行比较,看是否有不一致。
或者可以这样做:打开一个新的项目,创建一个新的硬件组态。在CPU的MPI接口的属性中为地址和传送速度设置各自的值。将'空'项目写入存储卡中。把该存储卡插入到CPU 然后重新打开CPU的电压,将位于存储卡上的设置传送到CPU。现在已经传送了MPI接口的当前设置,并且像这样的话,只要接口没有故障就可以建立连接。这个方法适用于所有具有存储卡接口的S7-CPU。
23.错误OB的用途是什么?
如果发生一个所描述的错误(见文件1),则将调用并处理相应OB。如果没有加载该OB,则CPU进入STOP(例外:OB70、72、7 3和81) 。
S7-CPU可以识别两类错误:
1) 同步错误:这些错误在处理特定操作的过程中被触发,并且可以归因于用户程序的特定部分。
2) 异步错误:这些错误不能直接归因于运行中的程序。这些错误包括优先级类的错误,自动化系统中的错误(故障模块)或者冗余的错误。
24. 在DP从站或CPU315-2DP型主站里应该编程哪些“故障 OBs”?
在组态一个作为从站的CPU315-2DP站时,必须在STEP7程序中编程下列OB以便评估分布式I/O类型的错误信息:
OB 82 诊断中断 OB 、OB 86 子机架故障 OB 、OB 122 I/O 访问出错。
1) 诊断OB82:如果一个支持诊断,并且已经对其释放了诊断中断的模块识别出一个错误,它既对进入事件也对外出的事件向 CPU 发出一个诊断中断的请求。操作系统然后调用 OB82。在 OB82 自己的局部变量里包含有有缺陷模块的逻辑基地址和 4 个字节的诊断数据。如果你还没有编程 OB82, 则 CPU 进入“停止”模式。你可以阻断或延迟诊断中断 OB ,并通过 SFC 39
- 42 重新释放它。
2) 子机架故障OB86:如果识别出一个 DP 主站系统或一个分布式 I/O 站有故障(既对进入事件也对外出的事件),该 CPU 的操作系统就调用 OB 86 。如果没有编程 OB 86 但出现了这样一个错误, CPU 就进入“停止”模式。你可以阻断或延迟 OB86 并通过 SFC 39 - 42 重新释放它。
3) I/O 访问出错OB122:当访问一个模块的数据时出错,该CPU的操作系统就调用OB 122。比方说,CPU在存取一个单个模块的数据时识别出一个读错误,那么操作系统就调用OB 122。该OB 122以与中断块有相同的优先级类别运行。如果没有编程OB 122,那么CPU由“运行”模式改为“停止”模式。
25.为什么在某些情况下,保留区会被重写?
在STEP 7的硬件组态中,可以把几个操作数区定义为“保留区”。这样可以在掉电以后,即使没有备份电池的话,仍能保持这些区域中的内容。如果定义一个块为 “保留块”,而它在 CPU 中不存在或只是临时安装过,那么这些区域的部分内容会被重写。在电源接通/断开之后,其他内容会在相关区里找到。
26.为何不能把闪存卡的内容加载入S7 300 CPU?
你的项目在闪存卡上。现在要用它加载 S7 300 。但加载结束后发现 CPU 的 RAM 中仍是空的。出现此问题的原因是你的程序里有无法处理的,'错误的'组织块(比如说, OB86 没有 DP 接口)。在重新设置和重新启动 CPU 后, RAM 仍是空的。诊断缓冲区对这个'无法加载'的块会提示一些信息。
27.当把 CPU315-2DP 作为从站,把 CPU315-2DP 作为主站时的诊断地址
在组态一个 CPU315-2DP 站时,你使用 S7 工具 “H/W CONFIG” 来分配诊断地址。如果发生一个故障,这些诊断地址被加入诊断 OB 的变量 “OB82_MDL_ADDR” 里。你可在 OB82 里分析此变量,确定有故障的站并作出相应的反应。
下面是如何分配诊断地址的例子:
第 1 步:通过 CPU315-2DP 组态从站并赋予一个诊断地址,比如 422;
第 2 步:通过 CPU315-2DP 组态主站;
第 3 步:把组态好的从站链接到主站并赋予一个诊断地址,比如 1022;
28.需要为S7-300 CPU的DP从站接口作何种设置,才可以使用它来进行路由选择?
如果使用CPU作为I-Slave,并且该CPU也起S7 路由器的作用,那么请注意如下事项:
用于路由选择的从站的DP接口必须设置为活动状态。这可以在HW Config中完成:在DP接口的属性对话框中,选项' Commissioning/Test operation'或'Programming, status/modify...'必须激活。关于这些设置的注意事项可以在下表中获得。
对于S7 路由连接,有 4 种可用的连接资源-与其它任何连接资源无关。没有使用PG/OP的连接资源或S7基本通信。
如果必须通过DP接口来建立一个与位于其机架上的通信伙伴连接时(如在 CP 343-1 中),也要使用一个路由连接。而对于通过MPI接口与一个位于其机架上的通信伙伴的连接,则不使用路由连接资源,因为在这种情况下,能够直接到达伙伴。注意事项:这不适用于CPU 318。
29.为什么当使用S7-300 CPU的内部运行时间表时,没有任何返回值?
当对CPU 312IFM到316-2DP参数化系统功能块 SFC2, SFC3 和 SFC4 时,为一个运行时间表规定了一个大于 'B#16#0'的标识符,那么将出错并且所需的功能也无法用。此种情况下,将在块的' RETVAL'输出处输出标识符 '8080h' 。
说明:对于这些 CPU,只有一个计时器可用。因此你应该只用标识符 'B#16#0'。在一个周期块(OB1, OB35)里一定不能调用系统功能 SFC2 'SET_RTM',而是应该在重启动OB(OB100)调用它。你也可以通过外部触发器来启动该块。不然的话,该块将老是复位运行计时表,永远完成不了计数。
30.变量是如何储存在临时局部数据中的?
L 堆栈永远以地址“0”开始。在 L 堆栈中,会为每个数据块保留相同个数的字节,作为存放每个块所拥有的静态或局部数据。
当某个块终止时,那么它的空间随之也被重新释放出来。指针总是指向当前打开块的第一个字节。
31.在CPU经过完全复位后是否运行时间计数器也被复位?
使用S7-300时,带硬件时钟(内置的 “实时时钟”)和带软件时钟的 CPU 之间有区别。对于那些无后备电池的软件时钟的 CPU,运行时间计数器在 CPU 被完全复位后其最后值被删除。而对于那些有后备电池的硬件时钟的 CPU,运行时间计数器的最后值在 CPU 被完全复位后被保留下来。同样, CPU 318 和所有的 S7-400 CPU 的运行时间计数器在 CPU
被完全复位后其最后值被保留。
32.如何把不在同一个项目里的一个S7 CPU组态为我的S7 DP主站模块的DP从站?
缺省情况下, 在STEP7里只可以把一个S7 CPU组态为从站,如果说该站是在同一个项目中的话。该站然后在“PROFIBUS-DP > 已经组态的站”下的硬件目录里作为“CPU 31x-2 DP”出现。用这种途径,可以设置起 DP 主站与 DP 从站间的链接。
还存在一个选项,可把一个与主站不在同一个项目里的S7 CPU组态为从站。进行如下:
按常规组态DP从站。
从网上下载要用作从站的S7-300 CPU的GSD文件。该文件位于客户支持网址的“PROFIBUS GSD 文件 / SIMATIC”下。
打开SIMATIC Manager 和硬件配置。
打开“选项 ; 安装新的 GSD...”,把刚下载的 GSD 文件插入硬件目录 。(注意:此过程中在 HW Config 中无须打开任何窗口) 。
通过“选项; 更新目录”来更新硬件目录。< ="">
现在可以组态你的 DP 主站。将可以在 “PROFIBUS-DP > 更多现场设备 > SPS” 下发现作为从站的该 S7-300 CPU 。
注意:如果是手动来结合该 DP 从站, 要确保总线参数,该 DP 从站的 PROFIBUS 地址 和它的 I/O 组态在两个项目里必须相同。
33.无备用电池情况下断电的影响与完全复位一样吗?
不一样。在CPU被完全复位的情况下,其硬件配置信息被删除(MPI地址除外),程序被删除, 剩磁存储器也被清零。
在无备用电池和存储卡的情况下关电,硬件配置信息(除了MPI地址) 和程序被删除。然而,剩磁存储器不受影响。如果在此情况下重新加载程序,则其工作时采用剩磁存储器的旧值。比方说,这些值通常来自前 8 个计数器。如果不把这一点考虑在内,会导致危险的系统状态。
建议:无备用电池和存储卡的情况下断电后,总是要做一下完全复位。
34.以将2线制传感器连接到紧凑型CPU的模拟输入端吗?
可以将2线制和4线制的传感器连接到CPU 300C的模拟输入端。使用一个2线制传感器时,在硬件组态中将“I = 电流”设置为测量类型,与4线制传感器的设置一样。
注意事项:请注意紧凑型CPU仅支持有源传感器( 4 线制传感器)。如果使用无源传感器( 2 制传感器),必须使用外部电源。
警告:请注意所允许的最大输入电流。2 线制传感器在出现短路时可能会超出最大允许电流。技术数据中规定的最大允许电流是50mA(破坏极限)。对于这种情况(例如,对 2 线制传感器加电流限制或与传感器串联一个PTC热敏电阻),确保提供足够保护。
35.SM322-1HH01也能在负载电压为交流 24 V的情况下工作吗?
是的,您也可以在负载电压为交流 24 V的情况下使用SM322-1HH01。
36.要确保SM322-1HF01 接通最小需要多大的负载电压和电流?
SM322-1HF01 继电器模块需要 17 V和 8 mA才能确保开闭正常。对于触点的寿命来说,这样的值比手册上提供的这个模块的值(10 V和 5 mA)更好。手册的规定值应该认为是最低要求值。
37.需要为哪些24V数字量输入模块(6ES7 321-xBxxx- ...)连接电源?
24V数字量输入模块的电源插针连接 (L+ / M) 。
38.在 ET200M 里是否也能使用 SM321 模块(DI16 x 24V)?
模块 SM321 (MLFB 6ES7 321-7BH00-0AB0) 也可在 ET200M 里使用。其中 CPU 31x-2DP 作为 DP 主站或者是通讯处理器 CP CP342-5 作为 DP 主站。同样该模块可以通过 ET200M 和 S7-400 通讯处理器 CP443-5 连接到一个S7-400 CPU。
39.SM323数字卡所占用的地址是多少?
SM323模块有 16 位类型(6ES7 323-1BL00-0AA0)和 8 位类型(6ES7 323-1BH00-0AA0)两种。对于 16 位类型的模块,输入和输出占用“X”和“X+1” 两个地址。如果 SM323 的基地址为 4 (即 X=4;插槽为 5),那么输入就被赋址在地址 4 和 5 下面, 输出的地址同样也被赋址在地址 4 和 5
下面。在模块的接线视图中,输入字节“X”位于左边的顶部,输出字节“X”在右边的顶部。
对于 8 位类型的模块,输入和输出各占用一个字节,它们有相同的字节地址。若用固定的插槽赋址,SM323 被插入槽 4, 那么输入地址为I 4.0 至 I 4.7,输出地址为 Q 4.0 至 Q 4.7。
40.在不改变硬件配置的情况下,能用SM321-1CH20 代替SM321-1CH80 吗?
SM321-1CH20 和SM321-1CH80 模块的技术参数是相同的。区别仅在SM321-1CH80 可以应用于更广泛的环境条件。因此您无需更改硬件配置。
41.进行I/O的直接访问时,必须注意什么?
需要注意在一个S7-300组态中,如果进行跨越模块的I/O直接读访问(用该命令一次读取几个字节),那么就会读到不正确的值。可以通过hardware中查看具体的地址。
42.SM321模块是否需要连接到 DC 24V 上?
不需要,如果是 MLFB 为 6ES7 321-1BH02-0AA0 的 SM 321 模块,就不再需要连接 DC 24V 了。
43.在 STEP 7 硬件组态中如何规划模拟模块 SM374?在硬件目录中如何找到此模块?
模拟模块SM374可用于三种模式中:作为 16 通道数字输入模块,作为 16 通道数字输出模块,作为带 8 个输入和 8 个输出的混合数字输入/输出模块。
现在把SM374按照您需要模拟的模块来组态,就是说;
如果把 SM 374 用作为一个 16 通道输入模块,则组态一个 16 通道输入模块 - 推荐使用:SM 321: 6ES7321-1BH01-0AA0;
如果把 SM 374 用作为一个 16 通道输出模块,则组态一个 16 通道输出模块 - 推荐使用:SM 322: 6ES7322-1BH01-0AA0;
如果把 SM 374 用作为一个混合输入/输出模块,则组态一个混合输入/输出模块( 8 个输入,8 个输出) - 推荐使用:SM 323: 6ES7323-1BH01-0AA0。
44.当测量电流时,出现传感器短路的情况,模块6ES7 331-1KF0.-0AB0的模拟量输入I+是否会被破坏?
当测量电流时,出现传感器短路的情况,模块6ES7 331-1KF0.-0AB0的模拟输入 I+不会被破坏。该模块具有内置的过流保护功能。模块中每个50欧姆的电阻器前面具有一个PTC元件,用于防止模块的输入通道被破坏。
请注意,输入电压允许的长期最大值为12V,短暂(最多1秒)值为30V。
45.如果切断CPU,则 2 线制测量变送器是否继续供电?
如果变送器模块插入位置“D”,且模块在引脚 1 和引脚 20 上由外部电压供电,则 2 线测量变送器继续供电。即使切断CPU,其供电电流仍维持不变。
46.用S7-300模拟量输入模块测量温度(华氏)时,可以使用模块说明文档中列出的绝对误差极限吗?
不可以直接使用指定的误差极限。基本误差和操作误差都以绝对温度和摄氏温度说明。必须乘以系数1.8将其转换为华氏温度单位。
例:S7-300 AI 8 x RTD:指定的温度输入操作误差是+/-1.0摄氏度。当以华氏温度测量时,可接受的最大误差是+/-1.8华氏度。
47.为什么用商用数字万用表在模拟输入块上不能读出用于读取阻抗的恒定电流?
几乎所有的S5/S7 模拟输入设备仍然以复杂的方式工作,即,所有的通道都依次插到仅有的一个AD转换器上。该原理也适用于读取阻抗所必需的恒定电流。因此,要读的流过电阻的电流仅用于短期读数。对于有一个选定接口抑制'50Hz'和 8 个参数化通道的SM331-7KF02-0AB0 ,这意味着电流将会约每180ms流过一次,每次有20ms可读取阻抗。
48.为什么S7-300 模拟输出组的电压输出超出容差?端子S+和S-作何用途?
下列描述适用于所有模拟输出模块SM 332:
当使用模拟输出模块 SM 332 时,必须注意返回输入S+和S-的分配。它们起补偿性能阻抗的目的。当用独立的带有S+ 和S-的电线连接执行器的两个触点时,模拟输出会调节输出电压,以便使动作机构上实际存在的电压为所期望的电压。
如果想要获得补偿,那么执行器必须用 4 根电线连接。这意味着对于第一个通道,需要:
输出电压通过针脚 3 和针脚 6 连接到执行器;
分配执行器的针脚 4 和针脚 5。
如果不想获得补偿,只需在前面的开关上简单的跨接针脚3-4和针脚5-6。
注意事项:因为打开的传感器端子 (S+ 和S-),输出电压被调节到最大值 140 mV (用于 10V)。g 对于此分配,无法保持0.5 %的电压输出使用误差限制。
49.如何连接一个电位计到6ES7 331-1KF0-0AB0?
电位计的采样端和首端连接到 M+,末端连接 M-,并且 S- 和M-连接到一起。
注意: 最大的可带电阻是6K,如果电位计支持直接输出一个可变的电压,那么电位计的首端应该连接V+,M端连接M-。
50.如何把一个PT100温度传感器连接到模拟输入模块SM331?
PT100热电阻随温度的不同其电阻值随之变化。如果有一恒定电流流经该热电阻,该热电阻上电压的下降随温度而变化。恒定电流加在接点Ic+ 和 Ic-上。模拟模块SM331在M+和M-电测定电流的变化。通过测定电压就可以确定出温度。
PT100 到模拟输入组有三类连接:4 线连接可得到最精确的测定值。
* 注意:
1)3 线连接用的公式仅表明了模拟输入模块 SM331 (MLFB 号为6ES7 331-7Kxxx-0AB0)b ' 的实际测定过程。
2)在 S7-300 系列中,存在一些通过多次测定的模拟输入端。它们规定出公共返回线的线电阻并作数学补偿。所获精确度几乎与 4 线连接可比美。这样模块的一个例子就是SM331(MLFB号6ES7 331-7PF00-0AB0)。
3)所给出的公式仍然适用于主要的物理关系,但并不包含确定 PT100 电阻的有效测定过程。
3 三菱FX系列PLC
1.FX3G和FX3GA的区别?
●FX3GA: 输入输出端子排不可拆;FX3G可拆,这样更换PLC时无需拆线;
●FX3GA: 不能配选件电池;FX3G可以选配电池;
●FX3GA: 最多只能扩展一个BD通讯板(单通道扩展),FX3G 40点或以上可以扩展2个BD板(双通道扩展);
●FX3GA :国内组装;FX3G 完全国外生产。
2.FX3U替代FX2N,以及FX3UC替代FX2NC,需要做哪些调整和改动?
●FX3U(C)系列相对应FX2N(C)系列它们的尺寸是一样的,电柜安装无需改动;
●FX3U(C)系列输入/输出端子排大小位置相同,更换PLC无需拆线,可以直接拆下旧机端子排换到新机上;
●FX3UC和FX2NC的接线是完全一样;FX3U会比FX2N多一个输入信号类型选择S/S端子,需要将该端子和24V短接,而之前FX2N相应位置是空置的。
3.FX系列PLC下载线有哪些,它们的区别?
FX系列下载线有FX-USB-AW(原装)、USB-SC09-FX、USB-SC09、SC09
●FX-USB-AW是三菱原装FX专用下载线,电脑侧为USB接口,使用可靠方便;
●USB-SC09-FX是国产下载线仿三菱FX-USB-AW,电脑侧为USB接口,使用方便;
●USB-SC09是国产下载线,可用于FX系列PLC和A系列PLC,电脑侧为USB接口,使用方便;
●SC09是主要针对以前老式电脑(自带RS232C 9针接口),电脑侧为RS232接口,,现在电脑使用它需要一个USB转RS232的转接口方能连接使用,比如USB-RS232 2.0。
4.FX2N PLC用FX3U替代后,原来的模块需要更换吗?
●FX2N PLC用FX3U替代后,原来的功能扩展板(通讯用的BD板和特殊适配器如FX2N-485BD,FX2NC-232ADP)需要更换成FX3U系列对应的功能扩展板;
●扩展设备(输入输出模块,特殊功能模块如FX2N-16EX,FX2N-2AD)不用更换,可直接使用。
5.FX0N-65EC 扩展电缆是不是必须配一个FX2N-CNV-BC转换接头才能连接使用啊?
FX0N-65EC当连接FX2N-32ER/ET、FX2N-48ER/ET时,不需要加FX2N-CNV-BC。
6.FX2N系列PLC型号后缀ES/UL跟-001有什么区别?
●后缀为ES/UL为欧版型号,-001为中国大陆版。
●-ES/UL系列输入方式可通过S/S端子,而选择源型、漏型输入方式。而-001系列输入方式固定为漏型输入。
7.FX0N-65EC 是不是必须要加一条FX2N-CNV-BC转换接头才能连接使用啊?
FX0N-65EC当连接FX2N-32ER/T.FX2N-48ER/T时,不需要FX2N-CNV-BC;其他模块都需要加的。
8.FX1S,FX1N,FX2N,FX3G,FX3GA,FX3U(C)本体自带高速脉冲输出点可以控制多少轴?
●FX1S,FX1N可以控制独立2轴,最大输出100KHZ脉冲串;
●FX1NC可以控制独立2轴,最大输出10KHZ脉冲串;
●FX2N可以控制独立2轴,最大输出20KHZ脉冲串;
●FX3G,FX3GA 14/24点可以控制独立2轴,40/60点最大输出100KHZ脉冲串;
●FX3U,FX3UC可以控制独立3轴,最大输出100KHZ脉冲串。
9.FX1N的PLC能否扩展连接FX2N的输入输出模块、模拟量模块、定位模块等?
FX1N的PLC完全可以扩展连接FX2N的扩展模块。如FX2N-16EX、FX2N-16EYR、FX2N-4AD、FX2N-10GM、FX2N-20GM等。
10.FX系列PLC在运行中,电源LED发生灯灭或是闪烁怎么办?
拆除PLC上[24 ](工作电源)端子的接线确认是否恢复正常。
●如恢复正常的话,有可能是因为负载的短接或是过大的负载电流而造成工作电源容量超载从而启动了保护功能。
●如不能恢复正常的话,请联系专业技术人员进行维修。
11.FX3U-ENET-ADP与FX3U-ENET-L有什么区别,是否可以相互替代?
FX3U-ENET-L是以太网模块,FX3U-ENET-ADP是以太网口适配器;-L功能强大,可以替代ADP;反之能否替代,则要参考所使用到的功能能否满足,从而来判断。
●ENET-ADP和ENET-L都具有MELSOFT连接功能,该功能作用是通过以太网口与人机界面连接,如三菱、威纶触摸屏。
●ENET-ADP和ENET-L都具有MC协议(即三菱PLC专用协议),该功能作用是上位工控机等利用MC协议读取、写入以及控制PLC。
●ENET-L模块有大量缓冲区,具备缓存发送接收功能(1024字/次),可作为主站与第三方设备如仪器仪表等通讯, ENET-ADP只是一个通讯扩展口,没有这个功能。
12.FX3U-1PG能替代FX-1PG-E?
●FX3U-1PG是 FX2N-1PG/FX-1PG-E的升级版;性能提升脉冲输出可达200KHZ,他们的程序可以通用。
●FX3U-1PG只能用在FX3U PLC主机上面,替代之后确定主机是否为FX3U PLC。
13.三菱FX3G系列PLC如何和条形码扫描枪通讯?如何在三菱3G的PLC中读取条形码?
用RS指令就可以了,你要读扫描仪的条码肯定要知道他的通讯协议,是专用的还是MODBUS 协议,然后要知道条码的数据存储区域地址以及数据类型和大小,然后才好用RS指令去读取这个站址的条码存储区域地址的数据,如果是两个字则反馈的数据只要把这两个字的类容显示出来就好了。
14.准备试着做一个控制系统,控制一个步进电机,四个气缸,有四个接近开关输入,选什么型号的PLC划算?
这种简单的系统什么型号都可以,FX2N FX1S FX3U你都可以选,主要是晶体管输出就好了。
15.用PLC怎么控制伺服电机?
根据编码器的分辨率计算每转的距离,然后用脉冲控制。
16.三菱FX3U系列PLC的4ad模块的4-20ma电流输出对应的参数是多少呀?
800-4000。
17.PLC定位模块的使用必须配合伺服吗?
必须配合伺服,根据参数 定位数据向伺服放大器输出指令。

(答案不唯一,仅供参考,文章最后有福利)目录
一、基础知识点
二、第三方框架
三、算法
四、编码格式(优化细节)
五、其他知识点
设计模式是什么? 你知道哪些设计模式,并简要叙述?
设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情。1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。3). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。4). 观察者模式:KVO是典型的观察者模式,观察某个属性的状态,状态发生变化时通知观察者。5). 委托模式:代理+协议的组合。实现1对1的反向传值操作。6). 工厂模式:通过一个类方法,批量的根据已有模板生产对象。
MVC 和 MVVM 的区别
MVVM是对胖模型进行的拆分,其本质是给控制器减负,将一些弱业务逻辑放到VM中去处理。MVC是一切设计的基础,所有新的设计模式都是基于MVC进行的改进。参考:iOS MVVM架构总结
#import跟 #include 有什么区别,@class呢,#import<> 跟 #import””有什么区别?
1). #import是Objective-C导入头文件的关键字,#include是C/C++导入头文件的关键字,使用#import头文件会自动只导入一次,不会重复导入。2). @class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含。3). #import<>用来包含系统的头文件,#import””用来包含用户头文件。
frame 和 bounds 有什么不同?
frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父view的坐标系统)bounds指的是:该view在本身坐标系统中的位置和大小。(参照点是本身坐标系统)
Objective-C的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方法用继承好还是分类好?为什么?
答:Objective-C的类不可以多重继承;可以实现多个接口(协议);Category是类别;一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。
@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的
@property 的本质是什么?@property = ivar + getter + setter;“属性” (property)有两大概念:ivar(实例变量)、getter+setter(存取方法)“属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中的数据。 Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中,“获取方法” (getter)用于读取变量值,而“设置方法” (setter)用于写入变量值。
@property中有哪些属性关键字?/ @property 后面可以有哪些修饰符?
属性可以拥有的特质分为四类:1.原子性--- nonatomic 特质2.读/写权限---readwrite(读写)、readonly (只读)3.内存管理语义---assign、strong、 weak、unsafe_unretained、copy4.方法名---getter= 、setter=5.不常用的:nonnull,null_resettable,nullable
属性关键字 readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种情况下用?
1). readwrite 是可读可写特性。需要生成getter方法和setter方法。2). readonly 是只读特性。只会生成getter方法,不会生成setter方法,不希望属性在类外改变。3). assign 是赋值特性。setter方法将传入参数赋值给实例变量;仅设置变量时,assign用于基本数据类型。4). retain(MRC)/strong(ARC) 表示持有特性。setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1。5). copy 表示拷贝特性。setter方法将传入对象复制一份,需要完全一份新的变量时。6). nonatomic 非原子操作。不写的话默认就是atomic。atomic 和 nonatomic 的区别在于,系统自动生成的 getter/setter 方法不一样。对于atomic的属性,系统生成的 getter/setter 会保证 get、set
操作的完整性,而nonatomic就没有这个保证了。所以,nonatomic的速度要比atomic快。不过atomic可并不能保证线程安全。参考:[爆栈热门 iOS 问题] atomic 和 nonatomic 有什么区别?
什么情况使用 weak 关键字,相比 assign 有什么不同?
1.在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性。2.自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。
IBOutlet连出来的视图属性为什么可以被设置成weak?因为父控件的subViews数组已经对它有一个强引用。
不同点:assign 可以用非 OC 对象,而 weak 必须用于 OC 对象。weak 表明该属性定义了一种“非拥有关系”。在属性所指的对象销毁时,属性值会自动清空(nil)。
怎么用 copy 关键字?
用途:1. NSString、NSArray、NSDictionary 等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;2. block 也经常使用 copy 关键字。
说明:block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy
,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。
用@property声明的 NSString / NSArray / NSDictionary 经常使用 copy 关键字,为什么?如果改用strong关键字,可能造成什么问题?
答:用 @property 声明 NSString、NSArray、NSDictionary 经常使用 copy
关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作(就是把可变的赋值给不可变的),为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。
1. 因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。2. 如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
总结:使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发送变化会无意间篡改不可变类型对象原来的值。
浅拷贝和深拷贝的区别?
浅拷贝:只复制指向对象的指针,而不复制引用对象本身。深拷贝:复制引用对象本身。内存中存在了两份独立对象本身,当修改A时,A_copy不变。
系统对象的 copy 与 mutableCopy 方法
不管是集合类对象(NSArray、NSDictionary、NSSet ... 之类的对象),还是非集合类对象(NSString, NSNumber ... 之类的对象),接收到copy和mutableCopy消息时,都遵循以下准则:1. copy 返回的是不可变对象(immutableObject);如果用copy返回值调用mutable对象的方法就会crash。2. mutableCopy 返回的是可变对象(mutableObject)。
一、非集合类对象的copy与mutableCopy
在非集合类对象中,对不可变对象进行copy操作,是指针复制,mutableCopy操作是内容复制;
对可变对象进行copy和mutableCopy都是内容复制。用代码简单表示如下: NSString *str = @"hello word!"; NSString *strCopy = [str copy] // 指针复制,strCopy与str的地址一样 NSMutableString *strMCopy = [str mutableCopy] // 内容复制,strMCopy与str的地址不一样
NSMutableString *mutableStr = [NSMutableString stringWithString: @"hello word!"]; NSString *strCopy = [mutableStr copy] // 内容复制 NSMutableString *strMCopy = [mutableStr mutableCopy] // 内容复制
二、集合类对象的copy与mutableCopy (同上)
在集合类对象中,对不可变对象进行copy操作,是指针复制,mutableCopy操作是内容复制;
对可变对象进行copy和mutableCopy都是内容复制。但是:集合对象的内容复制仅限于对象本身,对集合内的对象元素仍然是指针复制。(即单层内容复制) NSArray *arr = @[@[@"a", @"b"], @[@"c", @"d"]; NSArray *copyArr = [arr copy]; // 指针复制 NSMutableArray *mCopyArr = [arr mutableCopy]; //单层内容复制 NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil]; NSArray *copyArr = [mutableArr copy]; // 单层内容复制 NSMutableArray *mCopyArr = [mutableArr mutableCopy]; // 单层内容复制
【总结一句话】:只有对不可变对象进行copy操作是指针复制(浅复制),其它情况都是内容复制(深复制)!
*这个写法会出什么问题:@property (nonatomic, copy) NSMutableArray arr;
问题:添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃。//如:-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fcd1bc30460// copy后返回的是不可变对象(即 arr 是 NSArray 类型,NSArray 类型对象不能调用 NSMutableArray 类型对象的方法)原因:是因为 copy 就是复制一个不可变 NSArray 的对象,不能对 NSArray 对象进行添加/修改。
如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?
若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying 与 NSMutableCopying 协议。具体步骤:1. 需声明该类遵从 NSCopying 协议2. 实现 NSCopying 协议的方法。// 该协议只有一个方法:
(id)copyWithZone:(NSZone *)zone;// 注意:使用 copy 修饰符,调用的是copy方法,其实真正需要实现的是 “copyWithZone” 方法。
**写一个 setter 方法用于完成 @property (nonatomic, retain) NSString name,写一个 setter 方法用于完成 @property (nonatomic, copy) NSString name
// retain - (void)setName:(NSString *)str {
[str retain];
[_name release];
_name = str;
} // copy - (void)setName:(NSString *)str {
id t = [str copy];
[_name release];
_name = t;
}
@synthesize 和 @dynamic 分别有什么作用?
@property有两个对应的词,一个是@synthesize(合成实例变量),一个是@dynamic。如果@synthesize和@dynamic都没有写,那么默认的就是 @synthesize var = _var;// 在类的实现代码里通过 @synthesize 语法可以来指定实例变量的名字。(@synthesize var = _newVar;)1. @synthesize 的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。2. @dynamic 告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成(如,@dynamic var)。
常见的 Objective-C 的数据类型有那些,和C的基本数据类型有什么区别?如:NSInteger和int
Objective-C的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;NSInteger是基本数据类型,并不是NSNumber的子类,当然也不是NSObject的子类。NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef
long NSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本身是int还是long。
id 声明的对象有什么特性?
id 声明的对象具有运行时的特性,即可以指向任意类型的Objcetive-C的对象。
Objective-C 如何对内存管理的,说说你的看法和解决方法?
答:Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。1). 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。2). 手动内存计数MRC:遵循内存谁申请、谁释放;谁添加,谁释放的原则。3). 内存释放池Release Pool:把需要释放的内存统一放在一个池子中,当池子被抽干后(drain),池子中所有的内存空间也被自动释放掉。内存池的释放操作分为自动和手动。自动释放受runloop机制影响。
Objective-C 中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?
答:线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;在主线程执行代码,方法是performSelectorOnMainThread,如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:
Category(类别)、 Extension(扩展)和继承的区别
区别:1. 分类有名字,类扩展没有分类名字,是一种特殊的分类。2. 分类只能扩展方法(属性仅仅是声明,并没真正实现),类扩展可以扩展属性、成员变量和方法。3. 继承可以增加,修改或者删除方法,并且可以增加属性。
我们说的OC是动态运行时语言是什么意思?
答:主要是将数据类型的确定由编译时,推迟到了运行时。简单来说, 运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
为什么我们常见的delegate属性都用是week而不是retain/strong?
答:是为了防止delegate两端产生不必要的循环引用。@property (nonatomic, weak) id delegate;
什么时候用delete,什么时候用Notification?
Delegate(委托模式):1对1的反向消息通知功能。Notification(通知模式):只想要把消息发送出去,告知某些状态的变化。但是并不关心谁想要知道这个。
什么是 KVO 和 KVC?
1). KVC(Key-Value-Coding):键值编码 是一种通过字符串间接访问对象的方式(即给属性赋值)举例说明:stu.name = @"张三" // 点语法给属性赋值[stu setValue:@"张三" forKey:@"name"]; // 通过字符串使用KVC方式给属性赋值stu1.nameLabel.text = @"张三";[stu1 setValue:@"张三" forKey:@"nameLabel.text"]; // 跨层赋值2). KVO(key-Value-Observing):键值观察机制 他提供了观察某一属性变化的方法,极大的简化了代码。KVO只能被KVC触发,包括使用setValue:forKey:方法和点语法。// 通过下方方法为属性添加KVO观察
(void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
// 当被观察的属性发送变化时,会自动触发下方方法
(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
KVC 和 KVO 的 keyPath 可以是属性、实例变量、成员变量。iOS 成员变量,属性变量,局部变量,实例变量,全局变量 详解
KVC的底层实现?
当一个对象调用setValue方法时,方法内部会做以下操作:1). 检查是否存在相应的key的set方法,如果存在,就调用set方法。2). 如果set方法不存在,就会查找与key相同名称并且带下划线的成员变量,如果有,则直接给成员变量属性赋值。3). 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值。4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
KVO的底层实现?
KVO基于runtime机制实现。探究KVO的底层实现原理
ViewController生命周期
按照执行顺序排列:1. initWithCoder:通过nib文件初始化时触发。2. awakeFromNib:nib文件被加载的时候,会发生一个awakeFromNib的消息到nib文件中的每个对象。3. loadView:开始加载视图控制器自带的view。4. viewDidLoad:视图控制器的view被加载完成。5. viewWillAppear:视图控制器的view将要显示在window上。6. updateViewConstraints:视图控制器的view开始更新AutoLayout约束。7. viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置。8. viewDidLayoutSubviews:视图控制器的view已经更新视图的位置。9. viewDidAppear:视图控制器的view已经展示到window上。10. viewWillDisappear:视图控制器的view将要从window上消失。11. viewDidDisappear:视图控制器的view已经从window上消失。
方法和选择器有何不同?
selector是一个方法的名字,方法是一个组合体,包含了名字和实现。
你是否接触过OC中的反射机制?简单聊一下概念和使用
1). class反射通过类名的字符串形式实例化对象。Class class = NSClassFromString(@"student");Student *stu = [[class alloc] init];将类名变为字符串。Class class =[Student class];NSString className = NSStringFromClass(class);2). SEL的反射通过方法的字符串形式实例化方法。SEL selector = NSSelectorFromString(@"setName");[stu performSelector:selector withObject:@"Mike"];将方法变成字符串。NSStringFromSelector(@selector(setName:));
调用方法有两种方式:
1). 直接通过方法名来调用。[person show];2). 间接的通过SEL数据来调用 。SEL aaa = @selector(show); [person performSelector:aaa];
如何对iOS设备进行性能测试?
答: Profile-> Instruments ->Time Profiler
开发项目时你是怎么检查内存泄露?
1). 静态分析 analyze。2). instruments工具里面有个leak可以动态分析。
什么是懒加载?
答:懒加载就是只在用到的时候才去初始化。也可以理解成延时加载。我觉得最好也最简单的一个例子就是tableView中图片的加载显示了, 一个延时加载, 避免内存过高,一个异步加载,避免线程堵塞提高用户体验。
类变量的 @public,@protected,@private,@package 声明各有什么含义?
@public 任何地方都能访问;@protected 该类和子类中访问,是默认的;@private 只能在本类中访问;@package 本包内使用,跨包不可以。
什么是谓词?
谓词就是通过NSPredicate给定的逻辑条件作为约束条件,完成对数据的筛选。//定义谓词对象,谓词对象中包含了过滤条件(过滤条件比较多)NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<%d",30];//使用谓词条件过滤数组中的元素,过滤之后返回查询的结果NSArray *array = [persons filteredArrayUsingPredicate:predicate];
isa指针问题
isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调
用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass)。根元类的isa指针指向本身,这样形成了一个封闭的内循环。
如何访问并修改一个类的私有属性?
1). 一种是通过KVC获取。2). 通过runtime访问并修改私有属性。
一个objc对象的isa的指针指向什么?有什么作用?
答:指向他的类对象,从而可以找到对象上的方法。
下面的代码输出什么?
@implementation Son : Father
(id)init {if (self = [super init]) {NSLog(@"%@", NSStringFromClass([self class])); // SonNSLog(@"%@", NSStringFromClass([super class])); // Son}return self;}@end// 解析:self 是类的隐藏参数,指向当前调用方法的这个类的实例。super是一个Magic Keyword,它本质是一个编译器标示符,和self是指向的同一个消息接收者。不同的是:super会告诉编译器,调用class这个方法时,要去父类的方法,而不是本类里的。上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *obj 这个对象。
写一个完整的代理,包括声明、实现
// 创建 @protocol MyDelagate @required -(void)eat:(NSString *)foodName;
@optional -(void)run;
@end //
声明 .h @interface person: NSObject
@end //
实现 .m @implementation person - (void)eat:(NSString *)foodName { NSLog(@"吃:%@!", foodName);
}
- (void)run { NSLog(@"run!");
}
@end
isKindOfClass、isMemberOfClass、selector作用分别是什么
isKindOfClass:作用是某个对象属于某个类型或者继承自某类型。isMemberOfClass:某个对象确切属于某个类型。selector:通过方法名,获取在内存中的函数的入口地址。
delegate 和 notification 的区别
1). 二者都用于传递消息,不同之处主要在于一个是一对一的,另一个是一对多的。2). notification通过维护一个array,实现一对多消息的转发。3). delegate需要两者之间必须建立联系,不然没法调用代理的方法;notification不需要两者之间有联系。
什么是block?
闭包(block):闭包就是获取其它函数局部变量的匿名函数。
block反向传值
*
在控制器间传值可以使用代理或者block,使用block相对来说简洁。
*
在前一个控制器的touchesBegan:方法内实现如下代码。 // OneViewController.m TwoViewController *twoVC = [[TwoViewController alloc] init];
twoVC.valueBlcok = ^(NSString *str) { NSLog(@"OneViewController拿到值:%@", str);
};
[self presentViewController:twoVC animated:YES completion:nil]; // TwoViewController.h
(在.h文件中声明一个block属性) @property (nonatomic ,strong) void(^valueBlcok)(NSString *str); // TwoViewController.m
(在.m文件中实现方法)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // 传值:调用block if (_valueBlcok) {
_valueBlcok(@"123456");
}
}
block的注意点
1). 在block内部使用外部指针且会造成循环引用情况下,需要用__week修饰外部指针:__weak typeof(self) weakSelf = self;2). 在block内部如果调用了延时函数还使用弱指针会取不到该指针,因为已经被销毁了,需要在block内部再将弱指针重新强引用一下。__strong typeof(self) strongSelf = weakSelf;3). 如果需要在block内部改变外部栈区变量的话,需要在用__block修饰外部变量。
BAD_ACCESS在什么情况下出现?
答:这种问题在开发时经常遇到。原因是访问了野指针,比如访问已经释放对象的成员变量或者发消息、死循环等。
lldb(gdb)常用的控制台调试命令?
1). p 输出基本类型。是打印命令,需要指定类型。是print的简写p (int)[[[self view] subviews] count]2). po 打印对象,会调用对象description方法。是print-object的简写po [self view]3). expr 可以在调试时动态执行指定表达式,并将结果打印出来。常用于在调试过程中修改变量的值。4). bt:打印调用堆栈,是thread backtrace的简写,加all可打印所有thread的堆栈5). br l:是breakpoint list的简写
你一般是怎么用Instruments的?
Instruments里面工具很多,常用:1). Time Profiler: 性能分析2). Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能。3). Allocations:用来检查内存,写算法的那批人也用这个来检查。4). Leaks:检查内存,看是否有内存泄露。
iOS中常用的数据存储方式有哪些?
数据存储有四种方案:NSUserDefault、KeyChain、File、DB。其中File有三种方式:writeToFile:atomically:、Plist、NSKeyedAchiever(归档)DB包括:SQLite、FMDB、CoreData
iOS的沙盒目录结构是怎样的?
沙盒结构:1. AppName.app 目录:这是应用程序的程序包目录,包含应用程序的本身。由于应用程序必须经过签名,所以您在运行时不能对这个目录中的内容进行修改,否则可能会使应用程序无法启动。2. Documents:您应该将所有的应用程序数据文件写入到这个目录下。这个目录用于存储用户数据。iCloud备份目录。(这里不能存缓存文件,否则上架不被通过)3. Library 目录:这个目录下有两个子目录:Preferences 目录:包含应用程序的偏好设置文件。您不应该直接创建偏好设置文件,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好.Caches 目录:用于存放应用程序专用的支持文件,保存应用程序再次启动过程中需要的信息。可创建子文件夹。可以用来放置您希望被备份但不希望被用户看到的数据。该路径下的文件夹,除Caches以外,都会被iTunes备份。4. tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能。
iOS多线程技术有哪几种方式?
答:pthread、NSThread、GCD、NSOperation
GCD 与 NSOperation 的区别:
GCD 和 NSOperation 都是用于实现多线程:GCD 基于C语言的底层API,GCD主要与block结合使用,代码简洁高效。NSOperation 属于Objective-C类,是基于GCD更高一层的封装。复杂任务一般用NSOperation实现。
写出使用GCD方式从子线程回到主线程的方法代码
答:dispatch_sync(dispatch_get_main_queue(), ^{ });
如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
// 使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。// 创建队列组dispatch_group_t group = dispatch_group_create();// 获取全局并发队列dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_group_async(group, queue, ^{ /*加载图片1 / });dispatch_group_async(group, queue, ^{ /加载图片2 / });dispatch_group_async(group, queue, ^{ /加载图片3 */ });// 当并发队列组中的任务执行完毕后才会执行这里的代码dispatch_group_notify(group, dispatch_get_main_queue(), ^{// 合并图片});
dispatch_barrier_async(栅栏函数)的作用是什么?
函数定义:dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
作用: 1.在它前面的任务执行结束后它才执行,它后面的任务要等它执行完成后才会开始执行。 2.避免数据竞争 // 1.创建并发队列 dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT); // 2.向队列中添加任务 dispatch_async(queue, ^{ // 1.2是并行的 NSLog(@"任务1, %@",[NSThread currentThread]);
}); dispatch_async(queue, ^{ NSLog(@"任务2, %@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{ NSLog(@"任务 barrier, %@", [NSThread currentThread]);
}); dispatch_async(queue, ^{ // 这两个是同时执行的 NSLog(@"任务3, %@",[NSThread currentThread]);
}); dispatch_async(queue, ^{ NSLog(@"任务4, %@",[NSThread currentThread]);
}); // 输出结果: 任务1 任务2 ——》 任务 barrier ——》任务3 任务4
// 其中的任务1与任务2,任务3与任务4 由于是并行处理先后顺序不定。
以下代码运行结果如何?
- (void)viewDidLoad {
[super viewDidLoad]; NSLog(@"1"); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"2");
}); NSLog(@"3");
} // 只输出:1。(主线程死锁)
什么是 RunLoop
从字面上看,就是运行循环,跑圈
其实它内部就是do-while循环,在这个循环内部不断地处理各种任务(比如Source、Timer、Observer)
一个线程对应一个RunLoop,基本作用就是保持程序的持续运行,处理app中的各种事件。
通过runloop,有事运行,没事就休息,可以节省cpu资源,提高程序性能。
主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个如下的main()函数int main(int argc, char * argv[]) {@autoreleasepool {return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}}RunLoop学习总结
说说你对 runtime 的理解
Runtime又叫运行时,是一套底层的C语言API,其为iOS内部的核心之一,我们平时编写的OC代码,底层都是基于它来实现的。
Runtime实现的机制是什么,怎么用,一般用于干嘛?
1). 使用时需要导入的头文件2). Runtime 运行时机制,它是一套C语言库。3). 实际上我们编写的所有OC代码,最终都是转成了runtime库的东西。比如:类转成了 Runtime 库里面的结构体等数据类型,方法转成了 Runtime 库里面的C语言函数,平时调方法都是转成了 objc_msgSend 函数(所以说OC有个消息发送机制)// OC是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。// [stu show]; 在objc动态编译时,会被转意为:objc_msgSend(stu, @selector(show));4). 因此,可以说 Runtime 是OC的底层实现,是OC的幕后执行者。
有了Runtime库,能做什么事情呢?Runtime库里面包含了跟类、成员变量、方法相关的API。比如:(1)获取类里面的所有成员变量。(2)为类动态添加成员变量。(3)为类动态添加新的方法。(4)动态改变类的方法实现等。(Method Swizzling)因此,有了Runtime,想怎么改就怎么改。iOS:学习runtime的理解和心得
什么是 Method Swizzle(黑魔法),什么情况下会使用?
1). 在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助类别重名方法暴力抢先之外,还有更加灵活的方法 Method Swizzle。2). Method Swizzle 指的是改变一个已存在的选择器对应的实现的过程。OC中方法的调用能够在运行时通过改变,通过改变类的调度表中选择器到最终函数间的映射关系。3). 在OC中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用OC的动态特性,可以实现在运行时偷换selector对应的方法实现。4). 每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的方法实现。5). 我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP。6). 我们可以利用 class_replaceMethod 来修改类。7). 我们可以利用 method_setImplementation 来直接设置某个方法的IMP。8). 归根结底,都是偷换了selector的IMP。
_objc_msgForward 函数是做什么的,直接调用它将会发生什么?
答:_objc_msgForward是 IMP 类型,用于消息转发的:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发。
什么是 TCP / UDP ?
TCP:传输控制协议。UDP:用户数据协议。
TCP 是面向连接的,建立连接需要经历三次握手,是可靠的传输层协议。UDP 是面向无连接的,数据传输是不可靠的,它只管发,不管收不收得到。简单的说,TCP注重数据安全,而UDP数据传输快点,但安全性一般。
通信底层原理(OSI七层模型)
OSI采用了分层的结构化技术,共分七层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
介绍一下XMPP?
XMPP是一种以XML为基础的开放式实时通信协议。简单的说,XMPP就是一种协议,一种规定。就是说,在网络上传东西,XMM就是规定你上传大小的格式。
OC中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?
// 创建线程的方法 - [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]
- [self performSelectorInBackground:nil withObject:nil];
- [[NSThread alloc] initWithTarget:nil selector:nil object:nil];
- dispatch_async(dispatch_get_global_queue(0, 0), ^{});
- [[NSOperationQueue new] addOperation:nil]; // 主线程中执行代码的方法- [self performSelectorOnMainThread:nil withObject:nil waitUntilDone:YES];
- dispatch_async(dispatch_get_main_queue(), ^{});
- [[NSOperationQueue mainQueue] addOperation:nil];
tableView的重用机制?
答:UITableView 通过重用单元格来达到节省内存的目的: 通过为每个单元格指定一个重用标识符,即指定了单元格的种类,当屏幕上的单元格滑出屏幕时,系统会把这个单元格添加到重用队列中,等待被重用,当有新单元格从屏幕外滑入屏幕内时,从重用队列中找看有没有可以重用的单元格,如果有,就拿过来用,如果没有就创建一个来使用。
用伪代码写一个线程安全的单例模式
static id _instance;
+ (id)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
}); return _instance;
}
+ (instancetype)sharedData { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
}); return _instance;
}
- (id)copyWithZone:(NSZone *)zone { return _instance;
}
如何实现视图的变形?
答:通过修改view的 transform 属性即可。
在手势对象基础类UIGestureRecognizer的常用子类手势类型中哪两个手势发生后,响应只会执行一次?
答:UITapGestureRecognizer,UISwipeGestureRecognizer是一次性手势,手势发生后,响应只会执行一次。
字符串常用方法:
NSString str = @"abc123";NSArray arr = [str componentsSeparatedByString:@""]; //以目标字符串把原字符串分割成两部分,存到数组中。@[@"abc", @"123"];
如何高性能的给 UIImageView 加个圆角?
*
不好的解决方案:使用下面的方式会`强制Core Animation提前渲染屏幕的离屏绘制, 而离屏绘制就会给性能带来负面影响`,会有卡顿的现象出现。 self.view.layer.cornerRadius = 5.0f; self.view.layer.masksToBounds = YES;
*
正确的解决方案:使用绘图技术
- (UIImage *)circleImage { // NO代表透明 UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0); // 获得上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 添加一个圆 CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height); CGContextAddEllipseInRect(ctx, rect); // 裁剪 CGContextClip(ctx); // 将图片画上去 [self drawInRect:rect]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); // 关闭上下文 UIGraphicsEndImageContext(); return image;
}
*
还有一种方案:使用了贝塞尔曲线"切割"个这个图片, 给UIImageView 添加了的圆角,其实也是通过绘图技术来实现的。 UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
imageView.center = CGPointMake(200, 300); UIImage *anotherImage = [UIImage imageNamed:@"image"]; UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds
cornerRadius:50] addClip];
[anotherImage drawInRect:imageView.bounds];
imageView.image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
[self.view addSubview:imageView];
你是怎么封装一个view的
1). 可以通过纯代码或者xib的方式来封装子控件 2). 建立一个跟view相关的模型,然后将模型数据传给view,通过模型上的数据给view的子控件赋值 /**
*
纯代码初始化控件时一定会走这个方法
*/ - (instancetype)initWithFrame:(CGRect)frame { if(self = [super initWithFrame:frame]) {
[self setupUI];
} return self;
} /**
*
通过xib初始化控件时一定会走这个方法
*/ - (id)initWithCoder:(NSCoder *)aDecoder { if(self = [super initWithCoder:aDecoder]) {
[self setupUI];
} return self;
}
- (void)setupUI { // 初始化代码 }
HTTP协议中 POST 方法和 GET 方法有那些区别?
1. GET用于向服务器请求数据,POST用于提交数据2. GET请求,请求参数拼接形式暴露在地址栏,而POST请求参数则放在请求体里面,因此GET请求不适合用于验证密码等操作3. GET请求的URL有长度限制,POST请求不会有长度限制
请简单的介绍下APNS发送系统消息的机制
APNS优势:杜绝了类似安卓那种为了接受通知不停在后台唤醒程序保持长连接的行为,由iOS系统和APNS进行长连接替代。APNS的原理:1). 应用在通知中心注册,由iOS系统向APNS请求返回设备令牌(device Token)2). 应用程序接收到设备令牌并发送给自己的后台服务器3). 服务器把要推送的内容和设备发送给APNS4). APNS根据设备令牌找到设备,再由iOS根据APPID把推送内容展示
第一种:代理传值
第二个控制器: @protocol WJSecondViewControllerDelegate
- (void)changeText:(NSString*)text; @end @property(nonatomic,assign)iddelegate;
- (IBAction)buttonClick:(UIButton*)sender {
_str = sender.titleLabel.text;
[self.delegate changeText:sender.titleLabel.text];
[self.navigationController popViewControllerAnimated:YES];
}
第一个控制器:
- (IBAction)pushToSecond:(id)sender {
WJSecondViewController *svc = [[WJSecondViewController alloc]initWithNibName:@"WJSecondViewController" bundle:nil];
svc.delegate = self;
svc.str = self.navigationItem.title;
[self.navigationController pushViewController:svc animated:YES];
[svc release];
}
- (void)changeText:(NSString *)text{ self.navigationItem.title = text;
}
第二种:通知传值
第一个控制器: //注册监听通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(limitDataForModel:) name:@"NOV" object:nil];
- (void)limitDataForModel:(NSNotification *)noti{ self.gamesInfoArray = noti.object;
}
第二个控制器: //发送通知 [[NSNotificationCenter defaultCenter]
postNotificationName:@"NOV" object:gameArray];
第三种:单例传值
Single是一个单例类,并且有一个字符串类型的属性titleName
在第二个控制器:
- (IBAction)buttonClick:(UIButton*)sender {
Single *single = [Single sharedSingle];
single.titleName = sender.titleLabel.text;
[self.navigationController popViewControllerAnimated:YES];
}
第一个控制器:
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
Single *single = [Single sharedSingle]; self.navigationItem.title = single.titleName;
}
第四种:block传值
第二个控制器: @property (nonatomic,copy) void (^changeText_block)(NSString*);
- (IBAction)buttonClick:(UIButton*)sender {
_str = sender.titleLabel.text; self.changeText_block(sender.titleLabel.text);
[self.navigationController popViewControllerAnimated:YES];
}
第一个控制器:
- (IBAction)pushToSecond:(id)sender {
WJSecondViewController *svc = [[WJSecondViewController alloc]initWithNibName:@"WJSecondViewController" bundle:nil];
svc.str = self.navigationItem.title;
[svc setChangeText_block:^(NSString *str) {
>self.navigationItem.title = str;
}];
[self.navigationController pushViewController:svc animated:YES];
}
第五种:extern传值
第二个控制器: extern NSString *btn;
- (IBAction)buttonClick:(UIButton*)sender {
btn = sender.titleLabel.text;
[self.navigationController popViewControllerAnimated:YES];
}
第一个控制器: NSString *btn = nil;
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated]; self.navigationItem.title = btn;
}
第六种:KVO传值
第一个控制器:
- (void)viewDidLoad {
[super viewDidLoad];
_vc =[[SecondViewController alloc]init]; //self监听vc里的textValue属性 [_vc addObserver:self forKeyPath:@"textValue" options:0 context:nil];
}
第二个控制器:
- (IBAction)buttonClicked:(id)sender { self.textValue = self.textField.text;
[self.navigationController popViewControllerAnimated:YES];
}
Method1. performSelector方法
Method2. NSTimer定时器
Method3. NSThread线程的sleep
Method4. GCD
公用延迟执行方法
(void)delayMethod{ NSLog(@"delayMethodEnd");
Method1: performSelector
[self performSelector:@selector(delayMethod) withObject:nil/*可传任意类型参数*/ afterDelay:2.0];
注:此方法是一种非阻塞的执行方式,未找到取消执行的方法。
> 程序运行结束
> 2015-08-31 10:56:59.361 CJDelayMethod[1080:39604] delayMethodStart2015-08-31 10:56:59.363 CJDelayMethod[1080:39604] nextMethod2015-08-31 10:57:01.364 CJDelayMethod[1080:39604] delayMethodEnd
Method2: NSTimer定时器
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(delayMethod) userInfo:nil repeats:NO];
注:此方法是一种非阻塞的执行方式,
取消执行方法:`- (void)invalidate;`即可
> 程序运行结束
> 2015-08-31 10:58:10.182 CJDelayMethod[1129:41106] delayMethodStart2015-08-31 10:58:10.183 CJDelayMethod[1129:41106] nextMethod2015-08-31 10:58:12.185 CJDelayMethod[1129:41106] delayMethodEnd
Method3: NSThread线程的sleep
[NSThread sleepForTimeInterval:2.0];
注:此方法是一种阻塞执行方式,建议放在子线程中执行,否则会卡住界面。但有时还是需要阻塞执行,如进入欢迎界面需要沉睡3秒才进入主界面时。
没有找到取消执行方式。
> 程序运行结束
> 2015-08-31 10:58:41.501 CJDelayMethod[1153:41698] delayMethodStart2015-08-31 10:58:43.507 CJDelayMethod[1153:41698] nextMethod
Method4: GCD
__block ViewController/*主控制器*/ *weakSelf = self; dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0/*延迟执行时间*/ * NSEC_PER_SEC));
dispatch_after(delayTime, dispatch_get_main_queue(), ^{
[weakSelf delayMethod];
});
注:此方法可以在参数中选择执行的线程,是一种非阻塞执行方式。没有找到取消执行方式。
> 程序运行结束
> 2015-08-31 10:59:21.652 CJDelayMethod[1181:42438] delayMethodStart2015-08-31 10:59:21.653 CJDelayMethod[1181:42438] nextMethod2015-08-31 10:59:23.653 CJDelayMethod[1181:42438] delayMethodEnd
完整代码参见:
> // > // ViewController.m > // CJDelayMethod > // > // Created by 陈杰 on 8/31/15. > // Copyright (c) 2015 chenjie. All rights reserved. > // >
> # import "ViewController.h" >
> @interface ViewController () > @property (nonatomic, strong) NSTimer *timer;
> @end > @implementation ViewController* >
>
*`- (void)viewDidLoad { `*
>
> *` [super viewDidLoad]; `*
>
> *` NSLog(@"delayMethodStart"); `*
>
> *` [self methodOnePerformSelector];// `* >
> *` [self methodTwoNSTimer];// `* >
> *` [self methodThreeSleep];//`* >
> *` [self methodFourGCD]; `*
>
> *` NSLog(@"nextMethod");`*
>
> *`}`*
>
>
*`- (void)methodFiveAnimation{ `*
>
> *` [UIView animateWithDuration:0 delay:2.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{ } completion:^(BOOL finished) { `*
>
> *` [self delayMethod]; `*
>
> *` }];`*
>
> *`}`
> `- (void)methodFourGCD{ `*
>
> *` __block ViewController`*`weakSelf = self; dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)); dispatch_after(delayTime, dispatch_get_main_queue(), ^{ `
>
> ` [weakSelf delayMethod]; `
>
> ` });`
>
> `}`
>
>
`- (void)methodThreeSleep{ `
>
> ` [NSThread sleepForTimeInterval:2.0];`
>
> `}`
>
>
`- (void)methodTwoNSTimer{`
>
> ` NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(delayMethod) userInfo:nil repeats:NO];`
>
> `}`
>
>
`- (void)methodOnePerformSelector{`
>
> ` [self performSelector:@selector(delayMethod) withObject:nil/*可传任意类型参数*/ afterDelay:2.0];`
>
> `}`
>
>
`- (void)delayMethod{`
>
> ` NSLog(@"delayMethodEnd");`
>
> `}`
> `- (void)didReceiveMemoryWarning { `
>
> ` [super didReceiveMemoryWarning]; `
>
> ` // Dispose of any resources that can be recreated.` >
> `}`
>
> `@end`
NSPersistentStoreCoordinator , NSManaged0bjectContext 和NSManaged0bject中的那些需要在线程中创建或者传递
答:NSPersistentStoreCoordinator是持久化存储协调者,主要用于协调托管对象上下文和持久化存储区之间的关系。NSManagedObjectContext使用协调者的托管对象模型将数据保存到数据库,或查询数据。
您是否做过一部的网络处理和通讯方面的工作?如果有,能具体介绍一下实现策略么?
答:使用NSOperation发送异步网络请求,使用NSOperationQueue管理线程数目及优先级,底层是用NSURLConnetion,
你使用过Objective-C的运行时编程(Runtime Programming)么?如果使用过,你用它做了什么?你还能记得你所使用的相关的头文件或者某些方法的名称吗?
答:Objecitve-C的重要特性是Runtime(运行时),在#import 下能看到相关的方法,用过objc_getClass()和class_copyMethodList()获取过私有API;使用Method method1 = class_getInstanceMethod(cls, sel1);Method method2 = class_getInstanceMethod(cls, sel2);method_exchangeImplementations(method1, method2);
代码交换两个方法,在写unit test时使用到。
Core开头的系列的内容。是否使用过CoreAnimation和CoreGraphics。UI框架和CA,CG框架的联系是什么?分别用CA和CG做过些什么动画或者图像上的内容。(有需要的话还可以涉及Quartz的一些内容)
答:UI框架的底层有CoreAnimation,CoreAnimation的底层有CoreGraphics。
UIKit
Core Animation
Core Graphics
Graphics Hardware
使用CA做过menu菜单的展开收起(太逊了)
是否使用过CoreText或者CoreImage等?如果使用过,请谈谈你使用CoreText或者CoreImage的体验。
答:CoreText可以解决复杂文字内容排版问题。CoreImage可以处理图片,为其添加各种效果。体验是很强大,挺复杂的。
自动释放池是什么,如何工作
答:当您向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放.它仍然是个OC的对象,因此自动释放池定义的作用域内的其它对象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池就会被释放,池中的所有对象也就被释放。
NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?(虽然protocol和delegate这种东西面试已经面烂了…)
答:NSNotification是通知模式在iOS的实现,KVO的全称是键值观察(Key-value observing),其是基于KVC(key-value
coding)的,KVC是一个通过属性名访问属性变量的机制。例如将Module层的变化,通知到多个Controller对象时,可以使用NSNotification;如果是只需要观察某个对象的某个属性,可以使用KVO。对于委托模式,在设计模式中是对象适配器模式,其是delegate是指向某个对象的,这是一对一的关系,而在通知模式中,往往是一对多的关系。委托模式,从技术上可以现在改变delegate指向的对象,但不建议这样做,会让人迷惑,如果一个delegate对象不断改变,指向不同的对象。
你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用NSOperationQueue,实现了什么?请描述它和G.C.D的区别和类似的地方(提示:可以从两者的实现机制和适用范围来描述)。
答:使用NSOperationQueue用来管理子类化的NSOperation对象,控制其线程并发数目。GCD和NSOperation都可以实现对线程的管理,区别是
NSOperation和NSOperationQueue是多线程的面向对象抽象。项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。
既然提到G.C.D,那么问一下在使用G.C.D以及block时要注意些什么?它们两是一回事儿么?block在ARC中和传统的MRC中的行为和用法有没有什么区别,需要注意些什么?
答:使用block是要注意,若将block做函数参数时,需要把它放到最后,GCD是Grand Central Dispatch,是一个对线程开源类库,而Block是闭包,是能够读取其他函数内部变量的函数。
对于Objective-C,你认为它最大的优点和最大的不足是什么?对于不足之处,现在有没有可用的方法绕过这些不足来实现需求。如果可以的话,你有没有考虑或者实践过重新实现OC的一些功能,如果有,具体会如何做?
> 答:最大的优点是它的运行时特性,不足是没有命名空间,对于命名冲突,可以使用长命名法或特殊前缀解决,如果是引入的第三方库之间的命名冲突,可以使用link命令及flag解决冲突。
你实现过一个框架或者库以供别人使用么?如果有,请谈一谈构建框架或者库时候的经验;如果没有,请设想和设计框架的public的API,并指出大概需要如何做、需要注意一些什么方面,来使别人容易地使用你的框架。
> 答:抽象和封装,方便使用。首先是对问题有充分的了解,比如构建一个文件解压压缩框架,从使用者的角度出发,只需关注发送给框架一个解压请求,框架完成复杂文件的解压操作,并且在适当的时候通知给是哦难过者,如解压完成、解压出错等。在框架内部去构建对象的关系,通过抽象让其更为健壮、便于更改。其次是API的说明文档。
AFNetworking 底层原理分析
AFNetworking主要是对NSURLSession和NSURLConnection(iOS9.0废弃)的封装,其中主要有以下类:1). AFHTTPRequestOperationManager:内部封装的是 NSURLConnection, 负责发送网络请求, 使用最多的一个类。(3.0废弃)2). AFHTTPSessionManager:内部封装是 NSURLSession, 负责发送网络请求,使用最多的一个类。3). AFNetworkReachabilityManager:实时监测网络状态的工具类。当前的网络环境发生改变之后,这个工具类就可以检测到。4). AFSecurityPolicy:网络安全的工具类, 主要是针对 HTTPS 服务。
5). AFURLRequestSerialization:序列化工具类,基类。上传的数据转换成JSON格式(AFJSONRequestSerializer).使用不多。6). AFURLResponseSerialization:反序列化工具类;基类.使用比较多:7). AFJSONResponseSerializer; JSON解析器,默认的解析器.8). AFHTTPResponseSerializer; 万能解析器; JSON和XML之外的数据类型,直接返回二进制数据.对服务器返回的数据不做任何处理.9). AFXMLParserResponseSerializer; XML解析器;
描述下SDWebImage里面给UIImageView加载图片的逻辑
SDWebImage 中为 UIImageView 提供了一个分类UIImageView+WebCache.h, 这个分类中有一个最常用的接口sd_setImageWithURL:placeholderImage:,会在真实图片出现前会先显示占位图片,当真实图片被加载出来后再替换占位图片。
加载图片的过程大致如下:1.首先会在 SDWebImageCache 中寻找图片是否有对应的缓存, 它会以url 作为数据的索引先在内存中寻找是否有对应的缓存2.如果缓存未找到就会利用通过MD5处理过的key来继续在磁盘中查询对应的数据, 如果找到了, 就会把磁盘中的数据加载到内存中,并将图片显示出来3.如果在内存和磁盘缓存中都没有找到,就会向远程服务器发送请求,开始下载图片4.下载后的图片会加入缓存中,并写入磁盘中5.整个获取图片的过程都是在子线程中执行,获取到图片后回到主线程将图片显示出来
SDWebImage原理:调用类别的方法:1. 从内存(字典)中找图片(当这个图片在本次使用程序的过程中已经被加载过),找到直接使用。2. 从沙盒中找(当这个图片在之前使用程序的过程中被加载过),找到使用,缓存到内存中。3. 从网络上获取,使用,缓存到内存,缓存到沙盒。
参考:SDWebImage内部实现过程
友盟统计接口统计的所有功能
APP启动速度,APP停留页面时间等
1.不用中间变量,用两种方法交换A和B的值
// 1.中间变量 void swap(int a, int b) { int temp = a;
a = b;
b = temp;
} // 2.加法 void swap(int a, int b) {
a = a + b;
b = a - b;
a = a - b;
} // 3.异或(相同为0,不同为1\. 可以理解为不进位加法) void swap(int a, int b) {
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
2.求最大公约数
/** 1.直接遍历法 */ int maxCommonDivisor(int a, int b) { int max = 0; for (int i = 1; i <=b; i++) { if (a % i == 0 && b % i == 0) {
max = I;
}
} return max;
} /** 2.辗转相除法 */ int maxCommonDivisor(int a, int b) { int r; while(a % b > 0) {
r = a % b;
a = b;
b = r;
} return b;
} // 扩展:最小公倍数 = (a * b)/最大公约数
3.模拟栈操作
/**
*
栈是一种数据结构,特点:先进后出
*
练习:使用全局变量模拟栈的操作
*/ #include
#include
#include
//保护全局变量:在全局变量前加static后,这个全局变量就只能在本文件中使用 static int data[1024];//栈最多能保存1024个数据 static int count = 0;//目前已经放了多少个数(相当于栈顶位置) //数据入栈 push void push(int x){
assert(!full());//防止数组越界 data[count++] = x;
} //数据出栈 pop int pop(){
assert(!empty()); return data[--count];
} //查看栈顶元素 top int top(){
assert(!empty()); return data[count-1];
} //查询栈满 full bool full() { if(count >= 1024) { return 1;
} return 0;
} //查询栈空 empty bool empty() { if(count <= 0) { return 1;
} return 0;
} int main(){ //入栈 for (int i = 1; i <= 10; i++) {
push(i);
} //出栈 while(!empty()){ printf("%d ", top()); //栈顶元素 pop(); //出栈 } printf("\n"); return 0;
}
4.排序算法
选择排序、冒泡排序、插入排序三种排序算法可以总结为如下:
*
都将数组分为已排序部分和未排序部分。 1\. 选择排序将已排序部分定义在左端,然后选择未排序部分的最小元素和未排序部分的第一个元素交换。 2\. 冒泡排序将已排序部分定义在右端,在遍历未排序部分的过程执行交换,将最大元素交换到最右端。 3\. 插入排序将已排序部分定义在左端,将未排序部分元的第一个元素插入到已排序部分合适的位置。
选择排序 /** * 【选择排序】:最值出现在起始端 * * 第1趟:在n个数中找到最小(大)数与第一个数交换位置 * 第2趟:在剩下n-1个数中找到最小(大)数与第二个数交换位置 * 重复这样的操作...依次与第三个、第四个...数交换位置 * 第n-1趟,最终可实现数据的升序(降序)排列。 * / void selectSort(int
arr, int length) { for (int i = 0; i < length - 1; i++) { //趟数 for (int j = i + 1; j < length; j++) { //比较次数 if (arr[i] > arr[j]) { int temp = arr[i]; arr[i] = arr[j]; arr[j]
= temp; } } } } * 冒泡排序 / * 【冒泡排序】:相邻元素两两比较,比较完一趟,最值出现在末尾 * 第1趟:依次 比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第n个元素位置 * 第2趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第n-1个元素位置 * …… …… *
第n-1趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第2个元素位置 */ void bublleSort(int *arr, int length) { for(int i = 0; i < length - 1; i++) { //趟数 for(int j = 0; j < length - i - 1; j++) {
//比较次数 if(arr[j] > arr[j+1]) { int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } }
参考:8大排序算法图文讲解常用算法OC实现
5.折半查找(二分查找)
/**
*
折半查找:优化查找时间(不用遍历全部数据)
*
*
折半查找的原理:
*
1> 数组必须是有序的
*
2> 必须已知min和max(知道范围)
*
3> 动态计算mid的值,取出mid对应的值进行比较
*
4> 如果mid对应的值大于要查找的值,那么max要变小为mid-1
*
5> 如果mid对应的值小于要查找的值,那么min要变大为mid+1
*
*/ // 已知一个有序数组, 和一个key, 要求从数组中找到key对应的索引位置
int findKey(int *arr, int length, int key) { int min = 0, max = length - 1, mid; while (min <= max) {
mid = (min + max) / 2; //计算中间值 if (key > arr[mid]) {
min = mid + 1;
} else if (key < arr[mid]) {
max = mid - 1;
} else { return mid;
}
} return -1;
}
参考:请Review下面的代码,并根据iOS的编码规范做出正确的修改
1.在 Objective-C 中,enum 建议使用NS_ENUM和NS_OPTIONS宏来定义枚举类型。
//定义一个枚举(比较严密) typedef NS_ENUM(NSInteger, BRUserGender) {
BRUserGenderUnknown, // 未知 BRUserGenderMale, // 男性 BRUserGenderFemale, // 女性 BRUserGenderNeuter // 无性 }; @interface BRUser : NSObject @property (nonatomic, readonly, copy) NSString *name; @property (nonatomic, readonly, assign) NSUInteger age; @property (nonatomic, readonly, assign) BRUserGender gender;
- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age gender:(BRUserGender)gender; @end //说明: //既然该类中已经有一个“初始化方法” ,用于设置 name、age 和 gender 的初始值: 那么在设计对应 @property 时就应该尽量使用不可变的对象:其三个属性都应该设为“只读”。用初始化方法设置好属性值之后,就不能再改变了。 //属性的参数应该按照下面的顺序排列: (原子性,读写,内存管理)
2.避免使用C语言中的基本数据类型,建议使用 Foundation 数据类型,对应关系如下:
int -> NSIntegerunsigned -> NSUIntegerfloat -> CGFloat动画时间 -> NSTimeInterval
HomeKit,是苹果2014年发布的智能家居平台。
什么是 OpenGL、Quartz 2D?
Quatarz 2d 是Apple提供的基本图形工具库。只是适用于2D图形的绘制。OpenGL,是一个跨平台的图形开发库。适用于2D和3D图形的绘制。
ffmpeg框架:
ffmpeg 是音视频处理工具,既有音视频编码解码功能,又可以作为播放器使用。
谈谈 UITableView 的优化
1). 正确的复用cell;2). 设计统一规格的Cell;3). 提前计算并缓存好高度(布局),因为heightForRowAtIndexPath:是调用最频繁的方法;4). 异步绘制,遇到复杂界面,遇到性能瓶颈时,可能就是突破口;5). 滑动时按需加载,这个在大量图片展示,网络加载的时候很管用!6). 减少子视图的层级关系;7). 尽量使所有的视图不透明化以及做切圆操作;8). 不要动态的add 或者 remove 子控件。最好在初始化时就添加完,然后通过hidden来控制是否显示;9). 使用调试工具分析问题。
如何实行cell的动态的行高
如果希望每条数据显示自身的行高,必须设置两个属性,1.预估行高,2.自定义行高。设置预估行高 tableView.estimatedRowHeight = 200。设置定义行高 tableView.estimatedRowHeight = UITableViewAutomaticDimension。如果要让自定义行高有效,必须让容器视图有一个自下而上的约束。
说说你对 block 的理解
栈上的自动复制到堆上,block 的属性修饰符是 copy,循环引用的原理和解决方案。
block的循环引用;block的代码实现;为什么会造成循环引用;block是如何强引用self的;参考:Block 代码块中用到了self引用问题,导致循环引用
什么是野指针、空指针?
野指针:不知道指向了哪里的指针叫野指针。即指针指向不确定,指针存的地址是一个垃圾值,未初始化。空指针:不指向任何位置的指针叫空指针。即指针没有指向,指针存的地址是一个空地址,NULL。
什么是 OOA / OOD / OOP ?
OOA(Object Oriented Analysis) --面向对象分析OOD(Object Oriented Design) --面向对象设计OOP(Object Oriented Programming)--面向对象编程
多线程是什么
多线程是个复杂的概念,按字面意思是同步完成多项任务,提高了资源的使用效率,从硬件、操作系统、应用软件不同的角度去看,多线程被赋予不同的内涵,对于硬件,现在市面上多数的CPU都是多核的,多核的CPU运算多线程更为出色;从操作系统角度,是多任务,现在用的主流操作系统都是多任务的,可以一边听歌、一边写博客;对于应用来说,多线程可以让应用有更快的回应,可以在网络下载时,同时响应用户的触摸操作。在iOS应用中,对多线程最初的理解,就是并发,它的含义是原来先做烧水,再摘菜,再炒菜的工作,会变成烧水的同时去摘菜,最后去炒菜。
iOS 中的多线程
iOS中的多线程,是Cocoa框架下的多线程,通过Cocoa的封装,可以让我们更为方便的使用线程,做过C++的同学可能会对线程有更多的理解,比如线程的创立,信号量、共享变量有认识,Cocoa框架下会方便很多,它对线程做了封装,有些封装,可以让我们创建的对象,本身便拥有线程,也就是线程的对象化抽象,从而减少我们的工程,提供程序的健壮性。
GCD是(Grand Central Dispatch)的缩写 ,从系统级别提供的一个易用地多线程类库,具有运行时的特点,能充分利用多核心硬件。GCD的API接口为C语言的函数,函数参数中多数有Block,关于Block的使用参看这里,为我们提供强大的“接口”,对于GCD的使用参见本文
NSOperation与Queue
NSOperation是一个抽象类,它封装了线程的细节实现,我们可以通过子类化该对象,加上NSQueue来同面向对象的思维,管理多线程程序。具体可参看这里:一个基于NSOperation的多线程网络访问的项目。
NSThread
NSThread是一个控制线程执行的对象,它不如NSOperation抽象,通过它我们可以方便的得到一个线程,并控制它。但NSThread的线程之间的并发控制,是需要我们自己来控制的,可以通过NSCondition实现。
参看 iOS多线程编程之NSThread的使用
其他多线程
在Cocoa的框架下,通知、Timer和异步函数等都有使用多线程,(待补充).
在项目什么时候选择使用GCD,什么时候选择NSOperation?
项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。
项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。
KVO,NSNotification,delegate及block区别
KVO就是cocoa框架实现的观察者模式,一般同KVC搭配使用,通过KVO可以监测一个值的变化,比如View的高度变化。是一对多的关系,一个值的变化会通知所有的观察者。
NSNotification是通知,也是一对多的使用场景。在某些情况下,KVO和NSNotification是一样的,都是状态变化之后告知对方。NSNotification的特点,就是需要被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用也更灵活。
delegate 是代理,就是我不想做的事情交给别人做。比如狗需要吃饭,就通过delegate通知主人,主人就会给他做饭、盛饭、倒水,这些操作,这些狗都不需要关心,只需要调用delegate(代理人)就可以了,由其他类完成所需要的操作。所以delegate是一对一关系。
block是delegate的另一种形式,是函数式编程的一种形式。使用场景跟delegate一样,相比delegate更灵活,而且代理的实现更直观。
KVO一般的使用场景是数据,需求是数据变化,比如股票价格变化,我们一般使用KVO(观察者模式)。delegate一般的使用场景是行为,需求是需要别人帮我做一件事情,比如买卖股票,我们一般使用delegate。Notification一般是进行全局通知,比如利好消息一出,通知大家去买入。delegate是强关联,就是委托和代理双方互相知道,你委托别人买股票你就需要知道经纪人,经纪人也不要知道自己的顾客。Notification是弱关联,利好消息发出,你不需要知道是谁发的也可以做出相应的反应,同理发消息的人也不需要知道接收的人也可以正常发出消息。
将一个函数在主线程执行的4种方法
*
GCD方法,通过向主线程队列发送一个block块,使block里的方法可以在主线程中执行。 dispatch_async(dispatch_get_main_queue(), ^{ //需要执行的方法 });
* NSOperation 方法 NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; //主队列 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ //需要执行的方法 }];
[mainQueue addOperation:operation];
* NSThread 方法
[self performSelector:@selector(method) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES modes:nil];
[self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:YES];
[[NSThread mainThread] performSelector:@selector(method) withObject:nil];
*
RunLoop方法
[[NSRunLoop mainRunLoop] performSelector:@selector(method) withObject:nil];
如何让计时器调用一个类方法
计时器只能调用实例方法,但是可以在这个实例方法里面调用静态方法。
使用计时器需要注意,计时器一定要加入RunLoop中,并且选好model才能运行。scheduledTimerWithTimeInterval方法创建一个计时器并加入到RunLoop中所以可以直接使用。
如果计时器的repeats选择YES说明这个计时器会重复执行,一定要在合适的时机调用计时器的invalid。不能在dealloc中调用,因为一旦设置为repeats
为yes,计时器会强持有self,导致dealloc永远不会被调用,这个类就永远无法被释放。比如可以在viewDidDisappear中调用,这样当类需要被回收的时候就可以正常进入dealloc中了。
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
-(void)timerMethod
{ //调用类方法 [[self class] staticMethod];
}
-(void)invalid
{
[timer invalid];
timer = nil;
}
如何重写类方法
NSTimer创建后,会在哪个线程运行
id和NSObject*的区别
id是一个 objc_object 结构体指针,定义是
typedef struct objc_object *id
id可以理解为指向对象的指针。所有oc的对象 id都可以指向,编译器不会做类型检查,id调用任何存在的方法都不会在编译阶段报错,当然如果这个id指向的对象没有这个方法,该崩溃还是会崩溃的。
NSObject *指向的必须是NSObject的子类,调用的也只能是NSObjec里面的方法否则就要做强制类型转换。
不是所有的OC对象都是NSObject的子类,还有一些继承自NSProxy。NSObject *可指向的类型是id的子集。
static关键字的作用
回答一:
1.在函数体内定义的static他的作用域为该函数体,该变量在内存中只被分配一次,因此,其值在下次调用时仍维持上次的值不变;2.在模块内的static全局变量可以被模块内所有函数访问,但是不能被模块外的其他函数访问;3.在模块内的staic全局变量可以被这一模块内的其他函数调用,这个函数的使用范围被限制在这个模块内;4.在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝,也就是说只要是该类的对象,那么该对象的中被static修饰的成员变量都指向同一块地址。
回答二:
修饰局部变量:1.延长局部变量的生命周期,程序结束才会销毁。2.局部变量只会生成一份内存,只会初始化一次。3.改变局部变量的作用域。
修饰全局变量:1.只能在本文件中访问,修改全局变量的作用域,生命周期不会改2.避免重复定义全局变量
在OC中static关键字使用误区
1.使用static修饰实例变量是不被允许的2.使用static修饰了方法,也是错误的
参考:如何正确使用const,static,externOC中 static 与 const 的作用
使用 Swift 语言编程的优缺点总的来说,我认为使用 Swift 来作为编程语言的优点还是要远远大于缺点的,而且很多缺点苹果也在逐渐改善。
(传送门)
推荐阅读更多精彩内容
整理的比较全面的面试题(一)最近在面试,总结总结遇到的面试题. 基础问题 LRU算法 [内存管理]的一种页面置换算法,对于在内存中但又不用的[...在牛魔角上狂码阅读 1,388评论 0赞 0
整理的比较全面的面试题(三)ES 简介 一个高扩展、开源的全文检索和分析引擎,它可以准实时地快速存储、搜索、分析海量的数据。全文检索是指计算机...在牛魔角上狂码阅读 1,186评论 0赞 1
Android之跑马灯跑马灯在项目了其实应用的还比较多,特别是做多媒体的时候,音乐视频蓝牙等等经常用到。 比如音乐的专辑信息,蓝牙通话记...江南皮皮阅读 3,950评论 1赞 6

我要回帖

更多关于 四舍五入的方法取什么值 的文章

 

随机推荐