2017-03-13 20:33:33 u010958446 阅读数 684

根类不从其它类继承,但是类层次中的所有其它类都最终从根类继承下来。根类连同Objective-C语言,是Cocoa直接访问Objective-C运行环境或与之交互的基本途径。

Cocoa对象 根类是本文要介绍的内容,仅凭Objective-C语言和运行环境并不足以构造哪怕是最简单的面向对象的程序,至少是不容易的。还缺少一些东西:即所有对象公有的基本行为和接口的定义。根类正是提供了这些定义。

之所以叫根类,是因为它位于整个类层次(这里是指Cocoa的类层次)的根上。根类不从其它类继承,但是类层次中的所有其它类都最终从根继承下来。根类连同Objective-C语言,是Cocoa直接访问Objective-C运行环境或与之交互的基本途径。Cocoa对象的大部分对象行为能力都是从根类得到的。

Cocoa提供了两个根类:NSObject和NSProxyCocoa将后者定义为抽象类,用于表示其它对象的替身对象。因此NSProxy类在分布式对象架构中是很重要的。由于作用比较特别,NSProxy在Cocoa程序中出现频率很低。Cocoa开发者在提到根类时,几乎总是指NSObject。

本部分将讨论NSObject类,看看它如何与运行环境进行交互,以及它为所有Cocoa对象定义的基本行为和接口。其中主要是它为对象的内存分配、初始化、内存管理、内省、以及运行环境支持所声明的方法。这些概念是理解Cocoa的基础。

NSObject

NSObject是大多数Objective-C类层次的根类,它没有超类。其它类从NSObject继承访问Objective-C语言运行时系统的基本接口,它们的实例可以得到对象行为的能力。

虽然NSObject不是一个严格的抽象类,但它是个虚类。仅凭一个NSObject实例除了作为一个简单的对象外,不能完成任何有用的工作。为了在您的程序中加入特有的属性和逻辑,必须创建一个或多个从NSObject或其派生类继承下来的类。

NSObject采纳了NSObject协议(参见"根类—和协议"部分)。NSObject协议支持多个根对象。举例来说,NSProxy是另一个根类,它不是继承自NSObject,但采纳了NSObject协议,以便和其它Objective-C对象共用一个公共的接口

NSObject是Cocoa中所有类的根类,包括Foundation和Application Kit。

根类—和协议

NSObject不仅仅是一个类的名称,还是一个协议的名称。两者对于定义一个Cocoa对象都是必要的。NSObject协议指定了Cocoa中所有根类必须的基本编程接口,因此不仅NSObject类采纳了这个同名的协议,其它根类也采纳这个协议,比如NSProxy。NSObject类进一步指定了不作为代理对象的Cocoa对象的基本编程接口。

NSObject及类似的协议用于Cocoa对象的总体定义(而不是在类接口中包含那些协议),使多个根类成为可能。每个根类共用一个由它们采纳的协议定义的公共接口。

在另一种意义上,NSObject不仅仅是个“根”协议。虽然NSObject类没有正式采纳NSCopying、NSMutableCopying、和NSCoding协议,但它声明和实现了与那些协议相关的方法(而且,包含NSObject类的NSObject.h头文件中也包含上面提到的所有四个协议的定义)。对象拷贝、编码、和解码是对象行为的基本部分。很多子类(如果不是绝大多数的话)都希望采纳和遵循这些协议。

请注意:其它Cocoa类可以通过范畴将方法添加到NSObject中。这些范畴通常是一些非正式的协议,在委托中使用。它们允许委托对象选择实现范畴中的部分方法。然而,NSObject的范畴并不被认为是基本对象接口的一部分。

根类方法概述

NSObject根类和它采纳的NSObject协议及其它“根” 协议一起,为所有不作为代理对象的Cocoa对象指定了如下的接口和行为特征:

分配、初始化、和复制。NSObject类中的一些方法(包括一些来自协议的方法)用于对象的创建、初始化、和复制:

  • alloc和allocWithZone:方法用于从某内存区域中分配一个对象内存,并使对象指向其运行时的类定义。
  • init方法是对象初始化原型,负责将对象的实例变量设置为一个已知的初始状态。initialize和load是两个类方法,它们让对象有机会对自身进行初始化。
  • new是一个将简单的内存分配和初始化结合起来的便利方法。
  • copy和copyWithZone:方法用于拷贝实现这些(由NSCopying协议定义的)方法的类的实例。希望支持可变对象拷贝的类则需要实现mutableCopy和mutableCopyWithZone:(由NSMutableCopying协议定义)方法。

对象的保持和清理。下面的方法对面向对象程序的内存管理特别重要:

  • retain方法增加对象的保持次数。
  • release方法减少对象的保持次数。
  • autorelease方法也是减少对象的保持次数,但是以推迟的方式。
  • retainCount方法返回对当前的保持次数。
  • dealloc方法由需要释放对象的实例变量以及释放动态分配的内存的类实现。

更多信息请参见 Cocoa对象的生命周期

内省和比较。NSObjec有很多方法可以查询对象的运行时信息。这些内省方法有助于找出对象在类层次中的位置,确定对象是否实现特定的方法,以及测试对象是否遵循某种协议。这些方法中的一部分仅实现为类方法。

  • superclass和class方法(实现为类和实例方法)分别以Class对象的形式返回接收者的超类和类。
  • isKindOfClass:和isMemberOfClass:方法来确定对象属于哪个类。后者用于测试接收者是否为指定类的实例。
  • isSubclassOfClass:类方法则用于测试类的继承性。
  • respondsToSelector:方法用于测试接收者是否实现由选择器参数标识的方法。instancesRespondToSelector:类方法则用于测试给定类的实例是否实现指定的方法。
  • conformsToProtocol:方法用于测试接收者(对象或类)是否遵循给定的协议。
  • isEqual:和hash方法用于对象的比较。
  • description方法允许对象返回一个内容描述字符串;这个方法的输出经常用于调试(“print object”命令),以及在格式化字符串中和“%@”指示符一起表示对象。

更多信息请参见 内省 。

对象的编码和解码。下面的方法和对象的编解码(作为归档过程的一部分)有关:

  • encodeWithCoder:和initWithCoder:是NSCoding协议仅有的方法。前者使对象可以对其实例变量进行编码,后者则使对象可以根据解码过的实例变量对自身进行初始化。
  • NSObject类中声明了一些于对象编码有关的方法:classForCoder:、replacementObjectForCoder:、和awakeAfterUsingCoder:

消息的转发。forwardInvocation:和相关的方法允许一个对象将消息转发给另一个对象。

消息的派发。以performSelector...开头的一组方法使您可以在指定的延迟后派发消息,以及将消息从辅助线程派发(同步或异步)到主线程。

NSObject还有几个其它的方法,包括一些处理版本和姿态(后者使一个类在运行时将自己表示为另一个类)的类方法,以及一些访问运行时数据结构的方法,比如方法选择器和指向方法实现的函数指针。

接口规范

某些NSObject方法只是为了被调用,而另一些方法则是为了被重载。举例来说,大多数子类不应该重载allocWithZone:方法,但必须实现init方法—至少需要实现一个最终调用根类的init方法(请参见"对象的创建"部分)的初始化方法。对于那些期望子类重载的方法,NSObject的实现或者什么也不做,或者返回一个合理的值,比如self。这些缺省实现使我们有可能向任意的Cocoa对象—甚至是没有重载这些方法的对象—发送诸如init这样得基本消息,而又不必冒运行时例外的风险。在发送消息之前,不必进行检查(通过respondsToSelector:方法)。更加重要的是,NSObject的这些“占位”方法为Cocoa对象定义了一个公共的结构,并建立了一些规则,如果所有的对象都遵循这些规则,对象间的交互将更加可靠。

实例方法和类方法

运行环境系统以一种特殊的方式处理根类定义的方法。根类定义的实例方法可以由实例对象和类对象执行,因此所有类对象都可以访问根类定义的实例方法。对于任何类对象,如果对象中不包含同名的类方法,就可以执行根类的所有实例方法。

举例来说,一个类对象可以通过发送消息来执行NSObject的respondsToSelector:和performSelector:withObject:实例方法:

  1. SEL method = @selector(riskAll:);   
  2. if ([MyClass respondsToSelector:method])   
  3.     [MyClass performSelector:method withObject:self];  

请注意,只有根类中定义的实例方法才可以在类对象中使用。在上面的例子中,如果MyClass重新实现了respondsToSelector:或者performSelector:withObject:方法,则那些新的版本将只能用于实例对象。MyClass的类对象只能执行NSObject类定义的版本(当然,如果MyClass将respondsToSelector:或performSelector:withObject: 实现为类方法,而不是实例方法,则该类对象可以执行这些新的实现)。


2018-06-06 10:17:07 lyxleft 阅读数 3447

一、继承

      继承是指一个新类拥有被继承类(父类)的全部属性和方法。例如,只有继承NSObject,才有创建对象的能力。NSObject是大部分类的基类(根类,root class)。


      当A类继承B类,A类就拥有B类中所有成员变量(属性)和方法。这也是继承的主要目的。

      使用场景:当我们可以说通B是一个A时,就可以使用B继承A类。

      继承的好处:代码重用;继承的缺点:父类的改变影响所有的子类。子类与父类耦合度很高。当子类中需要有自己独特的行为,不想使用父类的方法,可以把父类的方法覆盖掉:直接在子类中用一样的名字写个方法。不用在.h中写,因为父类已经声明过了,直接在.m中重写。

      如果重写了父类的方法,但还想使用父类的功能。则使用super。用来调用父类的方法。可以认为,super就是指父类。

      在继承体系中方法调用的顺序:1)在自己类中找;2)如果没有就去父类中找;3)如果父类中没有,就去父类的父类中找……直到找到基类。

      OC中只有实现没有声明的方法,是私有方法,不能在外面直接访问。但是它不是绝对私有。

      继承的注意点:OC中,类方法也是可以继承的(通过子类的类名调用父类的类方法);类方法也是可以重写的;类方法可以和对象方法重名(+表示类方法,-表示对象方法);子类中不能定义与父类中同名的成员变量。

       OC是单继承:一个类只能继承一个直接父类;
       OC是多层继承:B类继承A类,C类可以继承B类……

二、分类

     分类(类别)作用:扩展已有类的功能

     1)为原来的类增加方法;

     2)在方法内部可以访问原有类的成员变量(但这些成员变量一定要定义在头文件中)

     操作方法:

     1)为原有的类创建一个分类;2)在分类中增加新的方法的声明和实现

     在左侧栏目文件夹处右键-New File-Objective-C File-File Type选Category-Class选你还要扩展的那个类-File填分类名称(不是文件名称)。

      注意点:

      1、分类中不能扩展原有类的成员变量!

      2、如果在分类用@property:在分类中只能生成getter setter方法的声明,不能生成方法的实现和成员变量。

      3、分类可以扩充系统自带的类的功能。例如,给NSObject增加分类会影响到所有的类,但是这个东西一定要谨慎使用(笔者之前扩展了UIButton类,导致真机上所有按钮点击功能异常,但测试发布时模拟器都正常,造成用户APP大面积坏死……)

      4、你不能在分类中定义与原有类同名方法,不同的分类之间也不可以有同名的方法。如果你在分类中增加了一个与原有类同名的方法,那么分类中的方法会覆盖原有类的方法。

      5、如果多个分类中有相同的方法,执行最后编译的方法。

      6、记得要#import 分类。

三、类扩展

      在.m文件中为类增加私有的成员变量(属性)和方法

      在左侧栏目文件夹处右键-New File-Objective-C File-File Type选extension-Class选你还要扩展的那个类-File填分类名称(不是文件名称)。但通常直接在原类.m文件里写:@interface 原有类名()——这是一个常用的方法,特别是在带xib的控制器页面,一些控件我们通常用类扩展的方式,存在扩展里面,这样使得这些控件成员是私有的,不会被外界干扰到。

      与分类不一样的是:类扩展的原类名称后面的括号中没有东西,也没有.m文件。

      注意:类扩展得到的属性和方法,都是私有的!在外界中无法直接使用,即无法直接get后者set到这些成员。但是可以在.h里提供方法接口来改变这些私有属性的情况。



2018-07-16 22:52:30 wj610671226 阅读数 89

iOS逆向学习笔记之–类unix目录和iOS目录认知

  • 类unix目录
/      根目录
/bin    binary 简写  存放用户级基础功能二进制文件,如:ls  ps 等
/boot   存放能使系统成功启动的所有文件  iOS目录中为空
/dev    存放BSD设备文件
/sbin   存放系统级功能二进制文件  如: netstat  reboot等
/etc    存放系统脚本及配置文件  如 passwd hosts   iOS中/etc是一个符号链接,实际指向/private/etc
/lib    存放系统库文件  iOS中此目录为空
/mnt    存放临时的文件系统挂在点. iOS中此目录为空
/private 存放两个目录  分别是/private/etc 和 /private/var/tmp
/usr    包含了大多数用户工具和程序
/var    存放一些经常更改的文件 比如日志/用户数据 其中/var/moblie和/var/root分别存放了moblie用户和root用户的文件
  • iOS独有的目录
    iOS系统目录除了拥有上面的目录以外,还包括以下目录结构。
/Applications 存放所有系统APP和来自Cydia的APP  不包括App Store中下载的APP
/Developer  iPhone设备连接Xcode成为测试机后生成的目录
/Library  存放一些提供系统支持的数据,/Library/MobileSubstrate存放所有基于CydiaSubstrate(原名MobileSubstrate)的插件
/System/Library: iOS文件系统中最重要的目录之一,存放大量系统组件
/System/Library/Frameworks 和 /System/Library/PrivateFrameworks 存放iOS中各种frameWork 
/User 用户目录(就是mobile的home目录), 实际指向/var/mobile,这里存放大量用户数库
    比如:
    /var/mobile/Media/DCIM 存放照片
    /var/mobile/Media/REcordings 存放录音文件
    /var/mobile/Library/SMS 存放短信数据库
    /var/mobile/Containers 存放App Store下载的APP
  • iOS8.0越狱设备目录结构
    这里写图片描述
2019-09-20 18:33:49 China_PengChao 阅读数 9

 首先我们探索来实例对象、类对象、元类之间的关系,执行下面代码可以看到class1、class2、class3打印结果一样,我们是不是可以认为类对象只有一个,元类是一个虚拟的类由系统帮我们创建,是类对象所属的类,而元类归属是根元类,根元类的归属是自身。

//实例对象 
Person *p = [[Person alloc] init];  

//类对象  
Class class1= [Person class];
Class class2= p.class;
Class class3= object_getClass(p);
NSLog(@"\n%p-\n%p-\n%p",class1,class2,class3);

//元类对象
Class class4= object_getClass(class3);
NSLog(@"\n%p",class4);

//打印结果
0x10cefc148-
0x10cefc148-
0x10cefc148

0x10cefc120

 为了探索类的底层,我们查看objc源码可以看到objc_class继承自objc_object,objc_object结构体里面存在着一个重要的属性isa指针,isa是isa_t类型它是一个联合体。通过lldb命令调试可以得出实例对象的isa指向的是它所属的类,类对象的isa指向的是它所属的元类,元类对象的isa指向的是根元类,根元类对象的isa指向的是根元类。根元类的父类是NSObject,NSObject的父类是nil。

struct objc_class : objc_object {
    // Class ISA;                //隐藏属性 占8个字节
    Class superclass;            //占8个字节
    cache_t cache;               //占16个字节 formerly cache pointer and vtable
    class_data_bits_t bits;      // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() { 
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }
    void setInfo(uint32_t set) {
        assert(isFuture()  ||  isRealized());
        data()->setFlags(set);
    }

    ······
}

struct objc_object {
private:
    isa_t isa;

public:

    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();

    // getIsa() allows this to be a tagged pointer object
    Class getIsa();

    ······
}

//联合体(节省消耗的一种结构)
union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};


// isa的初始化方法
inline Class 
objc_object::ISA() 
{
    assert(!isTaggedPointer()); 
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    return (Class)(isa.bits & ISA_MASK);
#endif
}

isa指针流程图:

superclass指针流程图:

 我们的方法、属性、协议存放在objc_class中的class_data_bits_t bits当中

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint32_t version;

    const class_ro_t *ro;

    method_array_t methods;         //方法列表
    property_array_t properties;    //属性列表
    protocol_array_t protocols;     //协议列表

    Class firstSubclass;
    Class nextSiblingClass;

    char *demangledName;

#if SUPPORT_INDEXED_ISA
    uint32_t index;
#endif

    void setFlags(uint32_t set) 
    {
        OSAtomicOr32Barrier(set, &flags);
    }

    void clearFlags(uint32_t clear) 
    {
        OSAtomicXor32Barrier(clear, &flags);
    }

    // set and clear must not overlap
    void changeFlags(uint32_t set, uint32_t clear) 
    {
        assert((set & clear) == 0);

        uint32_t oldf, newf;
        do {
            oldf = flags;
            newf = (oldf | set) & ~clear;
        } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
    }
};

类结构图如下:

 

2015-09-05 11:36:31 NameUseNsstring 阅读数 305

下图中是一段的类声明的语法展示,声明了一个叫做 MyClass的类,它继承于根类:NSObject。(根类可以被所有的其他类直接或间接继承。)


下图是一个方法的语法展示,方法的声明由以下几个部分构成:方法类型标识符,返回类型,一个或多个方法签名关键字,以及参数类型和名称。



2、创建类

1.1、新建Single View app模版项目,按Command + N新建文件,创建类Student,继承与NSObject


1.2、生成student.h  student.m


  • #import <Foundation/Foundation.h>  
  •   
  • @interface Student : NSObject  
  •   
  • @end  


  • #import "Student.h"  
  •   
  • @implementation Student  
  •   
  • @end  


1.3、在头文件里添加类成员变量和方法

@interface


  • #import <Foundation/Foundation.h>  
  •   
  • @interface Student : NSObject  
  • {  
  •     NSString *studentName;  
  •     NSInteger age;  
  • }  
  •   
  • -(void) printInfo;  
  • -(void) setStudentName: (NSString*) name;  
  • -(void) setAge: (NSInteger) age;  
  • -(NSString*) studentName;  
  • -(NSInteger) age;  
  • @end  

 

 

  • @interface 类的开始的标识符号,好比Java   C语言中的Class   
  • @end 类的结束符号
  • 继承类的方式:Class:Parent,如上代码Student:NSObject
  • 成员变量在@interface Class: Parent { .... }之间
  • 成员变量默认的访问权限是protected
  • 类成员方法在成员变量后面,格式是:: scope (returnType) methodName: (parameter1Type) parameter1Name;
  • scope指得是类方法或实例化方法。类方法用+号开始,实例化方法用 -号开始。

 

1.4、实现类中的方法

@implementation


  • #import "Student.h"  
  •   
  • @implementation Student  
  •   
  • -(void) printInfo  
  • {  
  •     NSLog(@"姓名:%@ 年龄:%d",studentName,studentAge);  
  • }  
  • -(void) setStudentName: (NSString*) name  
  • {  
  •     studentName = name;  
  • }  
  • -(void) setAge: (NSInteger) age  
  • {  
  •     studentAge = age;  
  • }  
  • -(NSString*) studentName  
  • {  
  •     return studentName;  
  • }  
  • -(NSInteger) age  
  • {  
  •     return studentAge;  
  • }  
  •   
  • @end  

 

1.5、在View中创建类对象,调用方法。


  • - (void)viewDidLoad  
  • {  
  •     [super viewDidLoad];      
  •     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
  •       
  •     Student *student = [[Student alloc]init];  
  •     [student setStudentName:@"张三"];  
  •     [student setAge:10];  
  •     [student printInfo];  
  •     [pool release];  
  •   
  • }  

 

 

  • Sutdent *student = [[Sutdent alloc] init];这行代码含有几个重要含义
  •  [Student alloc]调用Student的类方法,这类似于分配内存,
  •  [object init]是构成函数调用,初始类对象的成员变量。

 

打印结果:


  • 姓名:张三 年龄:10  

 

2、类的实例方法使用多个参数

2.1添加一个多参数的方法和实现


  • ....  
  • -(void) setNameAndAge:(NSString*) name setAge:(NSInteger) age;  
  • ....  



  • ....  
  • -(void) setNameAndAge:(NSString*) name setAge:(NSInteger) age  
  • {  
  •     studentName = name;  
  •     studentAge = age;  
  • }  
  • ....  

 

2.2调用


  • - (void)viewDidLoad  
  • {  
  •     [super viewDidLoad];      
  •     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
  •       
  •     Student *student = [[Student alloc]init];  
  •     [student setNameAndAge:@"李四" setAge:20];  
  •     [student printInfo];  
  •     [student release];  
  •     [pool release];  
  • }  

打印结果:


  • 姓名:李四 年龄:20  

 

3、自定义构造函数

3.1声明和实现构造函数


  • ....  
  • -(Student*) initWithNameAndAge:(NSString*) name setAge:(NSInteger) age;  
  • ....  


  • ....  
  • -(Student*) initWithNameAndAge:(NSString*) name setAge:(NSInteger) age  
  • {  
  •     self = [super init];  
  •       
  •     if ( self ) {  
  •         [self setNameAndAge:name setAge:age];  
  •     }  
  •       
  •     return self;  
  • }  
  • ....  

 

-(id)init 这个方法用于类的初始化创建,每一个类在创建的时候需要调用init方法,使用父类的init方法得到了self,这就可以做一些子类初始化的工作

3.2使用自定义构造函数:


  • - (void)viewDidLoad  
  • {  
  •     [super viewDidLoad];      
  •     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
  •     Student *student = [[Student alloc]initWithNameAndAge:@"rongfzh" setAge:6];  
  •     [student printInfo];  
  •     [student release];  
  •     [pool release];  
  • }  

ios 中的UIControl类

阅读数 291

iOS UIView

阅读数 457

没有更多推荐了,返回首页