当前位置: 首页 > 编程日记 > 正文

iOS开发几年了,你清楚OC中的这些东西么!!!?

iOS开发几年了,你清楚OC中的这些东西么!!!?

前言

几年前笔者是使用Objective-C进行iOS开发, 不过在两年前Apple发布swift的时候,就开始了swift的学习, 在swift1.2发布后就正式并且一直都使用了swift进行iOS的开发了, 之后就是对swift持续不断的学习, 近来swift3.0的发布, 更多的人会选择swift来进行iOS的开发看上去更是成为了一种趋势, 不过一个合格的iOS开发者对oc以及c语言的掌握是必不可少的技能, 本篇中主要是写一些大家平时都可能用到但是不一定知道的oc的东西

  1. oc中的对象的创建: 首先会通过 +(id)alloc 动态的分配所有的变量以及父类定义的变量所需要的足够内存, 同时会清除所有的分配的内存空间, 全部置为0
  2. 同时接着需要调用class的 -(id)init 方法, 这个方法给每个变量设置初始值
  3. 返回的类型为id, id是一个可以指向任意类型的指针(不用 * 号), 这个在一定程度上可以完成多态的效果
  4. 对oc中的class文件的理解: class, extension, category
    ZJPerson.h文件


    Snip20160817_4.png


    ZJPerson.m文件


    Snip20160817_5.png


    ZJPerson.m文件


    m
  5. [[XXObject alloc] init] 初始化方法不需要参数的时候, 和 [XXObject new] 方法相同

  6. 通过字面量来初始化对象, 例如
      NSString *string = @"string"; == [[NSString alloc] initWithString:@"string"];等初始化方法NSNumber *myBOOL = @YES; == [[NSNumber alloc] initWithBool:YES]; NSNumber *myFloat = @3.14f; == NSNumber *myInt = @42; == NSNumber *myLong = @42L; ==...
  7. oc(c)中多行宏的定义(这个在swift...中更方便直接一个全局的函数就搞定了): 在除了最后一行的每一行结尾加一条反斜杠 \

    定义.png


    使用.png
  8. 比较是否相同: 使用 if(a==b) {}, 如果a,b是对象类型, 那么比较的是指针是否相同, 而不是比较值是否相同, 如果a, b是基本类型(int, double...), 那么比较的是值是否相同; 使用if ([a isEqual: b]) { }, 则比较的是a,b的值是否相同
  9. 初始化基本类型的时候尽量设置初始值, 因为编译器分配的初始值并不确定, 但是对象类型会默认初始化为nil
  10. 条件判断: 当对象不为nil(有内存地址)的时候, 或者基本类型非0, 或者bool类型为true, 这个时候条件都为真, 其他情况条件为假
  11. oc中属性的getter和setter
    @property (nonatomic) NSString *name;

    • 例如当有这样一个name属性的时候, 默认是readWrite的, 编译器会自动生成一个set (setName:)和get(-(NSString *)name)方法, 这个时候可以通过set或者get方法访问到name, 如果申明为(readonly), 那么将只会生成get方法
      [self setName:@"set name"];
      NSString *getName = [self name];
      也可以通过点语法访问(实际上是会自动调用set和get方法)
      self.name = @"set name"; NSString *dotName = self.name;
    • 同时你可以重写name的get(懒加载...)和setter(拦截set方法)...
      对应name属性, 编译器会生成(synthesize)一个 _name 允许我们直接通过指针访问变量, 而不会调用get方法, 所以通过_xx访问的变量不会调用懒加载(get方法), 所以在写懒加载方法的时候, 不能使用self.xx(造成死循环), 而要使用_xx
      - (NSString *)name {
      // 这里面不能使用self.name , 因为点语法会调用这个get方法, 造成死循环
      if (_name == nil) {_name = @"name"; } return _name; }
    • 同时这个synthesize的名字我们是可以自己修改的, 使用如下的语法
      @synthesize name = customName;
    • 那么这个时候就不能通过 __name访问到name了, 因为我们已经指定了通过customName才能访问到了
      NSString *getName = customName;
    • 当然如果, 你是这样写的 @synthesize name;, 并没有指定名字, 这个时候访问的时候就直接使用变量名而不需要加下划线( _ )了 name = @"set name"; ?这个时候就比较爽了, 和swift,java这些一样, 不需要self,this了;
  12. oc的属性默认是atomic(原子的), 也就是说是线程安全的, 这个时候是不允许重写set和get方法的, 因为内部的setter和getter会做出处理, 保证线程安全, 但是我们经常使用的是noatomic, 因为访问的速度比较快, 并且可以自己重写getter和setter

  13. oc中的对象是动态管理(内存)的, 是分配在heap(堆)上所以需要一个指针来指向它(才能访问), 所以对象类型需要用 星号  NSString * str;
  14. oc中的对象管理在ARC下是用引用计数来管理的, 当有一个强引用对象A指向这个对象B的时候, B引用计数加一, 当这个对象A销毁的时候,B的引用计数减一, 直到B的引用计数为0的时候就被自动销毁, 当然这个时候如果A强引用B, B同时强引用A就造成了循环引用, 两者都不会被销毁, 就造成了内存泄漏, 解决方法是将一方标记为 weak 或者unsafe_unretained(垂悬指针, 和swift中的[unowned self]类似, 所以运用不当会造成野指针的问题)
  15. oc中的属性默认是strong的, 所以需要显示的指定为其他的(weak, unsafe_unretained...)
  16. NSObject * __weak someObject = [[NSObject alloc] init];, 这个someObject没有对象强引用他, 所以这行代码之后会立马被置为nil, NSObject * __weak someObject = self.someObject, 这个someObject在这行代码之后不会立刻被置为nil, 而是会在所在的代码块结束后被置为nil
  17. 对于属性的赋值(深浅拷贝)
      @property (nonatomic) NSString *name;NSMutableString *str = [NSMutableString stringWithString:@"初始"]; ViewController *ob = [ViewController new]; ob.name = str; ---- 浅拷贝 NSLog(@"%@", ob.name); --- 初始 [str appendString:@"+1"]; NSLog(@"%@", ob.name); --- 初始+1 这里出现ob.name改变的原因就是: 属性name是strong(默认)类型的,ob.name = str; 这行代码赋值后, 实际上只是name强指向了str, 所以当str的内容改变的时候, ob.name也改变了 NSLog(@"%@", ob.name); --- 初始 str = [NSMutableString stringWithString:@"改变"]; NSLog(@"%@", ob.name); --- 初始 但是这样的赋值, 直接改变str之后并不会影响原来的str的指针指向的内容, 所以ob.name仍然指向原来的str, 因此内容并未改变 如果将上面的 ob.name = str; 改为 ob.name = [str mutableCopy]; 那么将上面的两种操作都不会影响ob.name ---- 深拷贝 如果name被修饰为copy @property (nonatomic, copy) NSString *name; 那么上面的操作都不会改变ob.name的内容 ---- 深拷贝
  18. 分类(category)定义的函数和属性在运行时中和原生的class中定义的东西并没有区别At runtime, there’s no difference between a method added by a category and one that is implemented by the original class
  19. 不过分类中定义的属性, 编译器并不会自动生成getter和setter, 以及_XX变量来访问,需要自己提供getter和setter, 并且需要使用运行时才能绑定这个属性到这个类中, 实现原生类中定义的属性的效果
    ///例如可能是这样的使用static const void *propertyKey = &propertyKey;/// 将value通过运行时绑定到self objc_setAssociatedObject(self, propertyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); /// 将value在运行时中通过propertyKey取出绑定的值 id value = objc_getAssociatedObject(self, propertyKey);
  20. 同时分类也可以用来将一个复杂的类中的代码分块(swift的extension可以有相似的作用), 使得代码组织更好, 例如可以将tableView的delegate, 和Datasource在分类中实现,
        @implementation ViewController(tableview)- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { } ... @end
  21. 但是在使用category来扩展Cocoa的原生类的时候, 要注意函数的命名如果是和原生已有的函数名相同,那么将会发生不可预料的结果(不能确定哪一个方法在运行时会被调用), 因此建议在自己的函数名前面加上前缀, 就像重写 +load() 来实现各种黑魔法的时候也是可能会发生不可预料的结果, 因为同一个项目中可能有多个地方重写了这个类的 +load方法
  22. 初始化NSArray的时候, 如果通过NSArray *arr1 = @[object1, object2];, 不需要以nil结尾, 如果通过构造方法初始化, 则需要传入nil结尾, 同时, 如果中间的对象有nil, 那么将在中间nil就结束了, NSArray *arr2 = [NSArray arrayWithObjects:object1, object2, object3, nil, object4, object5, nil] 这个arr2只可能会存储第一个nil前的对象
  23. 如果在数组中一定要存储nil, 那么只能用NSNull来代替
  24. 如果NSArray中存储的是NSArray, NSDictionary, NSString, NSData, NSDate , NSNumber这些类型的对象, 那就可以直接写入disk并且读取disk的数据做持久化数据操作[array writeToURL:fileURL atomically:YES], 但是如果是有其他的类型, 就需要使用归档来实现了
  25. 在for-in快速枚举中, 不能够修改(增删)被枚举的对象(数组, 字典,集合)
  26. 在写代码的时候, 进行条件判断的时候, 经常会出现这样的代码  if (a = 1){...}, 这样写编译器是会报错的, 需要写成 if(a == 1) {...}, 当然你非要使用一个等号也是可以的, 需要额外加一个括号,  if ((a = 1)) {...}
  27. 实际上绝大多数情况下都是我们写条件判断的时候都是使用==, 而非 =, 也就只有当我们写构造方法的时候才可能会写到 =,像这样  if (self = [super init]) {...}, 其实这并不是使用=来判断条件相等是正确的, 只是在这里, 通过[super init]方法会返回一个id对象, 通过, self = [super init], 把这个对象赋值给self, 这个时候的 if就是用来判断, 被赋值后的self是否为nil, 而不是 self是否等于[super init]返回的对象.
  28. 在oc中block是object类型的, 所以是可以存储在NSArray...中, 同时在调用block的时候, 如果block为nil(未赋值), 那么程序将crash.
  29. oc中block可以捕获变量, 什么意思呢 --- 就是block会默认捕获到变量的值, 在之后不受到原来变量的改变的影响, 例如

          int anInteger = 42;void (^testBlock)(void) = ^{ NSLog(@"Integer is: %i", anInteger); }; anInteger = 84; testBlock(); ---- 输出的值仍然为 42
  30. 第二种block捕获变量的方式, 是捕获变量的指针, 被捕获的变量值改变, 则block中的变量值也改变了,不过需要对变量进行__block标记, 例如上面的代码, 只改变一点, 结果就变了

      __block int anInteger = 42;void (^testBlock)(void) = ^{ NSLog(@"Integer is: %i", anInteger); }; anInteger = 84; testBlock(); --- 输出值这时是 84
  31. 伴随着block能够捕获变量的能力的一个问题就是, 循环引用, 在ARC中, 只要不是用到纯C语言的库,管理内存的工作都不需要我们完成, 但是循环引用却是我们需要解决的, 最常见的就是当block捕获的变量是一个对象的属性(方法)的时候, 也就是会捕获到self, 那么这个时候就可能会造成循环引用(block属性应该被标记为copy), 解决方法也很简单, 使用一个对self弱引用的指针即可, 这个写法就很多了, 笔者习惯的写法是: __weak typeof(self) weakSelf = self;, 那么在block中使用weakSelf替代self调用相关的属性或者方法, 就不会造成循环引用
  32. 使用weakSelf能够解决block捕获self造成的循环引用的内存泄漏问题, 但是带来的另一个问题就是, 特别是在多线程中,可能在block中代码正在执行的时候, self被销毁了, 因为使用weakSelf捕获到的是self的弱引用, 那么后续的代码就不能够继续执行了, 这个时候为了保证在这个block中self即使被销毁block里面的代码也能正常执行, 我们需要的另一个操作就是, 将weakSelf强引用一次, 让他的引用计数加1, 就能处理这个问题, 就是Apple在wwdc中提到的weak-strong-dance, 笔者习惯的书写方式是: __strong typeof(self) strongSelf = weakSelf;,,, 当然这个必须要明白的是, 这个block里面的strongSelf能够保证里面代码执行完毕的前提是程序能够执行到block, 如果在执行block之前self已经被销毁了, 那么这个block肯定是不会被调用的(block的引用计数已经为0).

相关文章:

在做会员资料修改时,实现下拉菜单的默认项定位

作者&#xff1a;lshdic http://blog.csdn.net/lshdic/ <!--在写一个交友网站时碰到的问题,就是当会员修改资料时&#xff0c;如何定位SELECT的菜单列默认项&#xff0c;不过很容易就解决了--> <HTML> <HEAD> <META http-equivContent-Type contenttex…

NFS 文件共享的创建过程

nfs 文件共享的服务器 nfs服务需要两个软件包nfs-utils和portmap 启动nfs服务 # service portmap start # service nfs start # chkconfig nfs on 开机自动启动 配置文件&#xff1a; /etc/exports 想要共享某个文件则编辑配置文件 共享目录 共享IP&#xff08;共享属性&…

行业新风向!AI人才缺口30万,单个项目最高补贴1000万元!

最近&#xff0c;程序员届有一个重大好消息&#xff0c;可能很多人还不知道&#xff0c;那就是&#xff1a;国内某些城市已经开始程序员人才补贴了&#xff01;对于人工智能公司的项目开发、人才引进、科技研发&#xff0c;最高按照国拨经费的30%给予配套支持&#xff0c;单个项…

Robotium todolist.test.elements

2019独角兽企业重金招聘Python工程师标准>>> ElementsEditToDoItemActivity package com.example.todolist.test.elements;import android.widget.Button; import android.widget.EditText;import com.example.todolist.R; import com.robotium.solo.Solo;public cl…

经典的导航二级式导航菜单增强版

作者&#xff1a;lshdic http://blog.csdn.net/lshdic/<!--呵呵我发的上一版相信大家都看过了吧&#xff0c;想一想上一版的确是不怎么华丽&#xff0c;而且上一版是针对表格内的连接A而定位的而这一版的优点显然比上一版要华丽&#xff0c;速度一样快&#xff0c;而且是针…

【海洋女神原创】installshield 32位打包和64位打包的注意事项

32/64位问题要把握几点&#xff1a;1. 明确你的产品是否需要区分32/64位2. 明确你的产品中是否有32/64位的服务注册3. 了解InstallShield Build出来的安装包本身是32位应用程序4. 了解Windows 64位系统上的32位路径和64位路径差异以及如何在InstallShield的系统变量中找到对应的…

如何提高模型性能?这四大方法值得尝试 | CSDN 博文精选

作者 | BoCong-Deng编辑 | 屠敏封图 | 自东方 IC出品 | CSDN 博客写在前面在我们进行模型训练时&#xff0c;如果你只是想要让模型具有不错的性能&#xff0c;那么盲目地尝试网络架构足以达到目的。而在本文中&#xff0c; 我们将为你提供一套用于构建最先进深度学习模型的必备…

ORACLE11g 没有控制文件如何通过rman备份恢复数据的详细实战过程

1、副总裁需要裸恢复的严峻现实 集团总部的信息部负责人给我打电话说为了找一年前的记录&#xff0c;所以需要对一年前2015年5月1日的数据进行恢复。而2016年初因为进行迁移&#xff0c;所以有些文件可能丢失&#xff0c;手上只有rman全备文件&#xff0c;希望在一天之内找回&a…

C语言文件等题

1.#include <stdio.h>double fun(int n){ }main(){ int n; double s; printf("\nInput n: "); scanf("%d",&n); sfun(n); printf("\n\ns%f\n\n",s); NONO();}NONO(){/* 请在此函数内打开文件&#xff0c;输入测试数据&…

使用 Vml 制作立体柱状投票统计图的完整程序

作者&#xff1a;lshdic http://blog.csdn.net/lshdic/<!--以下便是完整的 JsVml 制作柱状投票统计图的完整程序,保存为HTM文件运行即可看到效果其中 array数组中的分组可以为6个也可以为2&#xff0c;3&#xff0c;4&#xff0c;5个等,运行以下程序需要您的浏览器支持VML…

Python, C++和Java代码互翻,Facebook开发首个自监督神经编译器

译者 | 刘畅出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;将早期的编程语言&#xff08;例如COBOL&#xff09;的代码库迁移到现在的编程语言&#xff08;例如Java或C&#xff09;是一项艰巨的任务&#xff0c;它需要源语言和目标语言方面的专业知识。COBOL如今仍在…

pinpoint的id的生成

traceId的生成 public String getTransactionId() {return TransactionIdUtils.formatString(agentId, agentStartTime, transactionSequence);}public static final String TRANSACTION_ID_DELIMITER "^";public static String formatString(String agentId, long …

X@X.X域名转向的实现

www.chinacs.net 中文C#技术站 当你看到csdncsdn.com时&#xff0c;你肯定把这当作电子邮件地址&#xff0c;其实这个不一定是邮件地址&#xff0c;有可能是域名。现在有越来越多的人开始使用这个形式的地址了。初看起来&#xff0c;你不要以为这个是一个什么非常了不起的技术&…

GPT-3 的到来,程序员会被 AI 取代吗?

无需任何训练&#xff0c;AI可用任何语言编程。作者 | Frederik Bussler译者 | 弯月&#xff0c;责编 | 晋兆雨头图 | CSDN 下载自东方 IC来源 | CSDN以下为译文&#xff1a;2017年的时候&#xff0c;曾有研究人员问&#xff1a;到2040年人工智能是否承担起大多数的编程工作&am…

iphone 下拉刷新控件 EGORefreshTableHeaderView 手动显示更新

参考资料:http://blog.csdn.net/ugg/article/details/7283661 在它基础上进行修改 EGORefreshTableHeaderView 绝对是ios开发中的必选插件,其用法就不再赘述. 为了能够手动的显示更新界面而不是要等到用户实际拖动才触发(比如程序刚启动时), 通过阅读它的代码可以发现,只要自己…

Eclipse create git repository failure(egit)

2019独角兽企业重金招聘Python工程师标准>>> 启动和创建的时候会出现这样的异常信息&#xff0c;具体处理办法如下&#xff1a; cd /path/to/yourRepo.git cd .. mkdir yourRepo mv yourRepo.git yourRepo cd yourRepo git config --local --bool core.bare false g…

如何用asp.net向其他服务器post一条信息

www.chinacs.net 中文C#技术站 using System;using System.Web;using System.Net;using System.IO;using System.Text;namespace SendMessage{ public bool SendMsg(MsgInfo msg){//create requesttry{WebRequest req WebRequest.Create("http://your_post_url");…

Directx11教程(11) 增加一个debug宏

现在我们在common.h中增加一个debug的宏&#xff0c;在每个d3d11函数后调用&#xff0c;如果d3d函数出错&#xff0c;它能够给出程序中错误的代码行数。 common.h代码如下&#xff1a; #pragma once #include <d3d11.h> #include <d3dx10math.h> #if defined(DEBUG…

为什么说机器学习是预防欺诈的最佳工具?

作者 | Giorgi Mikhelidze译者 | 天道酬勤&#xff0c;责编 | 晋兆雨头图 | CSDN付费下载自视觉中国随着现代技术的发展和完善&#xff0c;生活变得越来越舒适。虽然以前人们认为同时进行复杂的操作是不可能的&#xff0c;而如今计算机使这一任务变得很容易了。 与此同时&#…

集成支付宝钱包支付iOS SDK的方法与经验

没想到&#xff0c;支付宝的SDK是我目前用过的所有第三方SDK中最难用的一个了。 下载 首先&#xff0c;你要想找到这个SDK&#xff0c;都得费点功夫。现在的SDK改名叫移动支付集成开发包了&#xff0c;下载页面在 这里 的 “请点此下载集成开发包” Baidu和Googlep排在前面的支…

系统设计与架构笔记:ETL工具开发和设计的建议

好久没写博客了&#xff0c;不是自己偷懒&#xff0c;的确是没有时间哦。 最近项目组里想做一个ETL数据抽取工具&#xff0c;这是一个研发项目&#xff0c;但是感觉公司并不是特别重视,不重视不是代表它不重要&#xff0c;而是可能不会对这个项目要求太高&#xff0c;能满足我们…

如何获取主机的IP址址

http://www.aspcn.com 飞刀 &#xff08;如需转载&#xff0c;请注明文章来自http://www.aspcn.com 谢谢合作&#xff09; 这篇文章&#xff0c;我们不准备大规模的讨论技术问题。只是向大家介绍一下我们将如何获得一台主机的IP地址。在Win32 API中我们可以使用NetWork API完成…

炸裂!Google这波操作,预警了什么?

我们都知道谷歌爸爸收购了Cask Data一家公司。长期以来&#xff0c;谷歌致力于推动围绕 GoogleCloud 的企业业务&#xff0c;但在这方面一直被亚马逊和微软吊打&#xff0c;这次的收购正是为了弥补自身的短板。被收购的 Cask Data 是一家专门提供基于Hadoop的大型数据分析服务解…

百度地图设置div样式宽高为百分比不显示地图

如题&#xff0c;不显示地图只要在样式代码里面加以 position:absolute; 代码就可以了 <style type"text/css">body, html,#allmap {width:100%;height:100%;overflow: hidden;margin:0;font-family:"微软雅黑";position:absolute;}</style> 完…

在DataGrid中显示图片

兼谈 DadaGrid 模板列的创建DadaGrid 是 ASP.NET 编程中一个很重要的控件&#xff0c;其优良的可定制功能为提高它的表现力提供了极大的方便。除了与数据源直接绑定以外&#xff0c;我们还可以通过列绑定模板对 DataGrid 的列进行自定义&#xff0c;来按照我们设定的格式显示数…

程序员注意了!人社部“就业报告”:未来5年,这10个新职业有千万缺口

7月23日&#xff0c;人社部联合阿里钉钉发布了《新职业在线学习平台发展报告》&#xff0c;报告有两个核心思想&#xff1a;83%的80后遇到过职业危机&#xff0c;79%的90后担心失业。未来5年&#xff0c;物联网和人工智能人才缺口巨大&#xff0c;新职业人才需求高达千万 这上千…

编译内核出现make CONFIG_DEBUG_SECTION_MISMATCH=y错误

故障问题&#xff1a; 编译内核时出现“make CONFIG_DEBUG_SECTION_MISMATCHy” 错误提示&#xff1a; [rootserver linux-2.6.35.13]# make modules CHK include/linux/version.h CHK include/generated/utsrelease.h CALL scripts/checksyscalls.sh Build…

IOS UITabBarViewController 修改背景颜色

做iOS的都知道&#xff0c;每个项目都有UITabBarController。有的会自定义&#xff0c;有的采取系统&#xff0c;当时我也是用系统的&#xff0c;那时候还是小白&#xff0c;好多技术不太熟练&#xff0c;都用系统的&#xff0c;那时候还是1倍和2倍图片&#xff0c;那时候适配很…

ASP.NET的实时天气及24小时天气预报(C#)

ASP.NET的实时天气及24小时天气预报(C#) 修改其中的url获得其他城市的天气情况 如广州为&#xff1a; http://weather.yahoo.com/forecast/CHXX0037_c.html 注意仅适用于获得yahoo上的天气预报 GetWeather.aspx ----------------------------------- Weather24小时天气getWeath…

中科大硬核“毕业证”:“一生一芯”计划下,5位本科生带自研芯片毕业

作者 | 包云岗编辑 | 伍杏玲本文经作者授权转载自包云岗知乎【CSDN编者按】近日&#xff0c;中国科学院大学五位本科生的硬核“毕业证”引发IT圈热议&#xff0c;在“一生一芯”培养计划下&#xff0c;由五位2016级本科生主导完成一款64位RISC-V处理器SoC芯片设计并实现流片&am…