Objective c教程(Objective-C函数调用)

2024-07-23 06:30:05 :13

objective c教程(Objective-C函数调用)

大家好,objective c教程相信很多的网友都不是很明白,包括Objective-C函数调用也是一样,不过没有关系,接下来就来为大家分享关于objective c教程和Objective-C函数调用的一些知识点,大家可以关注收藏,免得下次来找不到哦,下面我们开始吧!

本文目录

Objective-C函数调用

Objective-c方法调用流程

Objective-c是一门动态语言,动态两个字主要就体现在我们调用方法的时候,运行时回动态的查找方法,然后调用相应的函数地址。运行时是整个Objective-c程序的基石,有了它我们的程序才能正常运行起来。

NSObject是Cocoa中绝大部分类的基类,它主要是提供了序列话,拷贝对象,以及支持运行时动态识别的框架。

在Objective-c中每一个类对象最开始的位置都会有一个isa指针,该指针指向一块内存区域,该部分主要包含两部分信息:

1、指向父类的指针。

2、自身的方法分发表。

有了这两部分,Objective-c的方法的调用流程就可以跑起来了。当我们调用一个对象的某一个方法的时候,首先会在当前类的分发表中寻找该方法,如果找不到对应的方法,然后再去其父类中寻找该方法,依次类推直到找到对应的方法为止,流程图如下:

你可能会想到,如果一个类有很深的继承层次,每次去调用根类的某个函数,岂不是都要做很多次查找。理论上是这个样子的,不过runtime也并非那么傻,它会为每一个类(不是对象)维护一个经常调用的方法的列表,只要调用过就会缓存起来(官方没有明确说明缓存机制),这样当程序运行稳定以后整个方法调用的过程就会更加高效。

通过学习官方文档Objective-C Runtime Programming Guide,可以发现其实所有的selector调用最后都会转化为C类型的函数调用。举个例子我们创建了一个A类型的对象aSample,然后调用其test方法(),编译的时候,编译器就会将该调用转化为objc_send(aSample, selector)的形式,runtime会调用test方法实现所对应的函数地址。该函数的参数包含了两个隐含的参数self以及_cmd,其中self指向调用该方法的对象,_cmd则代表要调用的方法。

前面提到了NSObject提供了很多遍历的方法可以和运行时进行交互,其中有个方法methodForSelector,通过它我们可以直接获取到指定的方法对应的函数指针。通常我们直接使用Objective-c方式的方法调用就可以了,但有时程序中可能会频繁的调用某一个方法,为了提高效率。我们可以直接获取到方法对应的函数地址,然后直接调用该函数,这样就少了动态识别的时间。

Object C如何实现类似iPhone界面切换的效果

oc里又一个官方的类叫 UIScrollView 就是干这个用的你先在创建一个他的对象,他有一个属性叫contentSize就是滑动的范围,既然是做iphoen桌面的所以高固定,宽不固定,所以高就是self.view.frame.height ,宽就是self.view.frame.width*(你想要几页就是几,最好别写死,根据你的小图标个数来),然后scrollView有个属性好像是叫 enablePage的,是个BOOL,写成YES;然后做你的每一页:创建一个UIView的类小图标做成UIView也可以,做成UIButton也可以,随你如果是UIView的话,做个单击的手势识别就可以有触发事件了。你会C++,那么你就写个循环创建这些小图标,一行4个,如果要iphone4的就是一页4行,如果是5的话就是5行,这个for循环你没问题吧。如果这一页够数儿了,就再创建新的一页。如果你老板还想要每页下面的小点点的话,就在加个UIPageControl这个类,小点点就出来了,再往下面的一行那个是固定的,你直接弄个uiview上面放4个按钮就可以了然后就是在UIScrollViewDelegate和UIPageControlDelegate的你用的到的方法里写事件就成了(记得把pageControl和scrollview关联上,是第几页第几个点点就亮起。)很简单,授之以鱼不如授之以渔,就不写代码了。再不明白,你就搜一下我提到的这2个类,会C++的话,一看就明白了

Objective-C

分类就是对装饰模式的一种具体实现。它的主要作用是在不改变原有类的前提下,动态地给这个类添加一些方法。 在分类中添加了一个属性时,只是声明了对应的set方法和get方法,并没有为我们在分类当中添加了实例变量。 如果要为分类添加实例变量,是通过关联对象来添加的。 分类结构体: category_t实际上就是我们创建的分类文件 这里没有实例变量的结构 从类别的结构体我们可以看到,分类可以添加属性,不能添加成员变量 当我们程序启动之后,在运行时会调用_objc_init方法,实际上是在runtime的初始化方法,然后会调用一系列方法,最后加载分类。 例如,调用_objc_init初始化方法后,会调用map_2_images方法,然后调用map_images_nolock方法,然后再调用_read_images,最后调用remethodizeClass:,分类的加载的逻辑都在remethodizeClass:方法的内部开始。 调用runtime的_objc_init方法,进行初始化操作,注册镜像状态改变时的回调函数,调用内存镜像相关处理的map_2_images函数,map_2_images主要是加锁并调用map_images_nolock,map_images_nolock完成所有 class 的注册、fixup等工作,还有初始化自动释放池、初始化 side table 等工作并在函数后端调用读取镜像函数_read_images,读取镜像函数_read_images加载可执行文件,比如加载类、Protocol、Category,最后调用remethodizeClass函数,分类的内部实现都在remethodizeClass函数里面。, 协议中可以定义:属性,方法 问题:我们在协议中声明的方法或者属性,代理方都必须实现吗? 不一定,在协议中被声明为require,是必须实现的,如果是optional的,可以不实现。 问题:代理方和委托方之间是是以什么样的关系存在的? 代理方用strong关键字来强持有委托方,委托方用weak关键字来声明代理方,弱引用代理方,这样的目的是以规避循环引用。 数据层,网络层,业务逻辑层,UI层 通知是怎样实现一对多的传递方式的 通知一对多的流程: 在通知中心(NSNotificationCenter)这个系统类当中,可能内部会维护一个Notification_Map表,或者说字典,这个字典当中的key是notificationName,即监听的通知名称,值就是就是我们添加的Observers_List,对于同一个名称的通知,添加多个Observer,所以Observer对应的值,应该是一个数组列表,这个列表中的每个成员,都包含通知接收的观察者和这个观察者调用的方法,比如说,我们收到这个通知之后,观察者的回调方法是哪个,那么在这个列表当中的每个元素里面也会体现关于这个通知回调方法的一些相关数据信息。 KVO是Key-value observing的缩写。 KVO是Objective-C对观察者设计模式的又一实现。 Apple使用了isa 混写(isa-swizzling)来实现KVO。 当我们调用了addObserver:forKeyPath:options:之后,系统在运行时动态创建NSKVONotifying_A这么一个子类,同时将原来的类A的isa指针指向新创建的类,重写set方法,来实现kvo的机制的。 NSKVONotifying_A是原来的类A的一个子类,之所以做这个继承关系,是为了重写A类的setter方法,然后这个子类对setter方法的重写来达到可以通知观察者的目的。 didChangeValueForKeyceiling这个方法就会触发 observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary《NSKeyValueChangeKey,id》 *)change context:(void *)context 回调方法来通知我们的观察者value发生了变化 KVC:是Key-value coding的缩写,键值编码技术,和键值编码技术相关的两个方法: 当调用value:forKey的时候,首先系统会判断我们通过这个key所访问的对应的实例变量是否有相应的getter方法,如果有,直接调用,然后结束value:forKey的调用流程; 如果对应的getter方法不存在,就会通过系统的+ (BOOL)accessInstanceVariablesDirectly判断实例变量是否存在,如果和我们这个key相同或者相似的成员变量存在的话,那么直接获取这个实例变量的值,然后结束value:forKey流程; 如果这个实例变量不存在,就会调用当前实例的valueForUndefinedKey:方法,然后会抛出NSUndefinedKeyException未定义key的异常,然后结束value:forKey调用流程。 我们在用value for key 获取一个key同名或者相似名称的成员变量的时候,访问器定义方法的定义,实际上也涉及到一个相似的概念,比如说,如果我们实现了get方法,叫getKey,同时满足驼峰命名方法,那么value for key的调用流程,也会认为这个key所对应的成员变量是存在访问器方法的。最常见的属性名称,也就是我们get方法的名称。除了《getKey》和《key》,还有《isKey》,如果说,我们传递参数的key,那么和它对应的成员变量,如果实现了一个叫isKey的get方法,那么在value for key调用流程当中也会认为它的访问器方法是存在的。 问题:实例变量是否存在的判断规则 只要存在_key、_isKey、key、isKey,就可以获取到对应的值。 调用setValue:forKey的时候,首先会判断是否有和这个key相关的Setter方法的存在,如果有,直接调用,然后结束setValue:forKey流程; 如果没有,就会通过系统的+ (BOOL)accessInstanceVariablesDirectly判断实例变量是否存在,如果这个实例变量存在的话,那么对这个key所对应的成员变量进行赋值,然后结束setValue:forKey流程; 如果这个实例变量不存在,就会调用当前实例的setValue:forUndefinedKey:方法,然后会抛出NSUndefinedKeyException未定义key的异常,然后结束setValue:forKey流程。 1)读写权限:readonly,readwrite(默认) 2)原子性: atomic(默认):赋值和获取,是线性安全的,但对于操作是不能保证线性安全的。 nonatomic 3)引用计数器 retain(MRC):修饰对象 strong(ARC):修饰对象 assign(修饰基本数据类型和对象类型) unsafe_unretained(MRC中使用比较频繁) weak copy 修饰基本数据类型,如int、BOOL等。 修饰对象类型时,不改变其引用计数。 会产生悬垂指针。 悬垂指针会造成内存泄露 assign所修饰的对象,在被释放之后,assign指针仍然指向原对象内存地址,这个时候,如果通过assign指针继续访问原对象的话,可能就会由于悬垂指针的原因造成内存泄露或者程序异常。 空指针:指针指向的地址为空的指针叫空指针(NULL指针) 野指针:是指向“垃圾”内存(不可用内存)的指针 产生原因:指针创建时未初始化。指针变量刚被创建时不会自动成为NULL指针,它会随机指向一个内存地址。 悬垂指针:指针所指向的对象已经被释放或者回收了,但是指向该对象的指针没有作任何的修改,仍旧指向已经回收的内存地址。 此类指针称为垂悬指针。 weak和assign都不改变对象的引用计数 浅拷贝的特点: 1、引用计数器增加。 2、不会开辟新的内存空间,不会发生新的内存分配。 深拷贝的特点: 1、不会增加被拷贝对象的引用计数 2、深拷贝产生新的内存分配 copy关键字 Block是将函数及其执行上下文封装起来的对象。 block本质上也是一个oc对象 Block调用即是函数的调用。 原因:__block修饰的变量变成了对象 栈上的__block的__forwarding指针是指向__block自身的。 impl.isa = &_NSConcreteStackBlock;(isa:标识当前block的类型) 1、_NSConcreteGlobalBlock 2、_NSConcreteStackBlock 3、_NSConcreteMallocBlock 不同类型的block在内存上面的分布: 1、全局类型的block:已初始化数据区 2、栈上面的block:栈区 3、堆上面的block:堆区 Block的copy操作 __block变量中是有一个__forwarding指针,栈上的__forwarding是指向block自身的,前提是栈上的。 我们在栈上创建了一个变量multiplier,如果通过__block修饰符修饰之后,multiplier就变成了一个对象,所以说multiplier=6 的赋值,实际上不是对变量赋值,而是通过multiplier这个对象的__forwarding指针,然后对其成员变量multiplier进行赋值,_blk实际上是某一个对象的成员变量,当对_blk进行赋值操作的时候,实际上就会对_blk进行copy操作,那么_blk就会被拷贝到堆上面去,然后我们对block进行执行,multiplier=6 代表的含义就是通过栈上的multiplier的__forwarding指针找到堆上面所对应的__block变量的copy副本,然后对其副本进行值的修改,右边block执行逻辑,我们调用了堆上面的block,入参为4,在我们调用的时候,这个时候我们在block的执行体当中所使用的multiplier __block变量,实际上使用的是堆上面的__block变量,那么我们在这里,实际上经过copy之后,multiplier=6 ,它是对堆上面的block变量的修改,所以我们在右边调用之后的结果是4和6的乘积为24。 当前对象用copy属性关键字声明了_strBlk,所以当前对象对_strBlk有一个强引用的,而_strBlk的表达式当中又使用到了_array成员变量,block截获变量的时候,对于对象类型的局部变量或者成员变量,实际上会连同属性关键字一起截获的,而array一般用strong属性关键字修饰的,所以在这个block中就有一个strong类型的指针指向当前对象,由此就产生了一个自循环引用。 会造成自循环引用,属于自循环。 解决方案:我们可以通过在当前栈上面创建一个__weak修饰符修饰的一个weakArray变量,来指向原对象的array成员变量,然后在block当中使用我们创建的weakArray,由此,我们就可以解除这个自循环引用。 在栈上面,我们通过__block修饰符修饰的变量来指向当前对象,同时当前对象的成员变量_blk在这里进行创建,block的表达式当中有使用到blockSelf的var变量。 在MRC下,不会产生循环引用,在ARC下,会产生循环引用,引起内存泄漏 ARC下的引用循环 ARC下的解决方案 MRC下同样没问题 这种解决方案有一个弊端:就是说如果我们很长一段时间或者说永远都不会调用_blk的话,那么这个引用循环的环就会一直存在。

请问学习iOS要学习objective-c基础教程,iPhone4与iPad基础开发教程以外,还有什么介绍

  • 若果这些你都熟悉的话,可以看看cocos2d系列的书,ios专门做游戏开发的,可以轻松的制作出很炫的效果。希望能帮助到你。

  • ios专门做游戏?我就郁闷了,我做应用做得好好的啊。那些地图啊,淘宝啊,优化大师啊,新浪微博这些不都是应用吗?要学什么就得看你想做那些,你想做游戏的话,看看cocos2d,想做3D游戏的话,还得再看看openGL,做应用的话,这两本书你搞定了,找项目练手就OK了。

Objective-C语法上有什么优点吗

OC确实有很多缺点,比如不安全, 其他的Java JavaScript swift 等都只有一个文件,他却又.h 和.m两个文件, 语法相对来说比较怪异, 底层算是c的结构体,c++指针,我个人觉得比Java和JavaScript要复杂一些,优点的话,也说不上就是有类似运行时,kvo,还是arc? 其实这些其他语言也有,所以不能成为什么优点,不过相对swift来说,他的优点可能就是编译速度快了,其他的也说不上。

如果要设计iOS系统的软件,需要学习哪些语言、代码、设计软件等

如过你想自己完整的独立完成,自己找个笔在纸上画出你构思的软件之后,首先要学后台代码,为您的软件搭建一个数据库,然后学习IOS开发,在做到前端后台的衔接,框架有了之后学习界面设计,之后在用到IOS开发技术进行设计图转代码,最后自己测试,申请个服务器,去应用商店申请发吧!设计软件一个SKETCH就够了

可以跳过Objective-C,然后直接学习Swift语言吗

Swift 结合了 C 和 Objective-C 的优点并且不受 C 兼容性的限制。

Swift 在 Mac OS 和 iOS 平台可以和 Object-C 使用相同的运行环境。

所以要学习 还是不跳过的好,分享点swift资料codingdict.com/article/6909

学objective-c前,需要先学c语言么

现在使用的实际上是objective-c 2.0,一般简称oc,算是c语言的一个超集;

简单说吧,如果没学过C语言,直接学习oc,在真正开发中,大多数情况下是没什么不妥的。毕竟很多东西你即使不懂也是一搜一大把的结果直接copy就完了。但如果你想要进阶,挑战更高的职位,c语言还是必须要会的,oc的底层全是c语言和c++写的,只有掌握了底层才能举一反三,从而写出更高级的代码来(绝不只是拿来装逼,实际写出的程序体验上完全是两个样)

以上就是我们为大家找到的有关“objective c教程(Objective-C函数调用)”的所有内容了,希望可以帮助到你。如果对我们网站的其他内容感兴趣请持续关注本站。

objective c教程(Objective-C函数调用)

本文编辑:admin
Copyright © 2022 All Rights Reserved 威海上格软件有限公司 版权所有

鲁ICP备20007704号

Thanks for visiting my site.