黑马程序员---Objective-C基础学习---类、对象、方法相关知识笔记

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

类、对象、方法相关知识笔记

  Objective-C相对于C语言有了面向对象的特性,但是ObjC又没有其他面向对象语言那么多语法特性,ObjC本身对面向对象进行了精简。下面是一些相关知识笔记。

  1. 类定义
  2. 成员变量
  3. 方法和属性
  4. self关键字

类定义

  在C#、Java等其他高级语言中定义一个类是相当简单点的,直接一个关键字class加一对大括号基本就完成了,但是在ObjC中类的定义相对变化比较大。现在假设需要定义一个Person类

在Xcode中添加文件,选择Cocoa Class 或者Cocoa Touch Class

输入类名Person,并选择父类为NSObject

默认生成如下两个文件

Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@end

Person.m

#import "Person.h"

@implementation Person

@end

在ObjC中定义一个类需要两个文件.h和.m:

  • .h文件:放类的声明,包括成员变量、属性和方法声明(事实上.h文件不参与编译过程);关键字@interface声明一个类,同时它必须以@end结束,在这两个关键字中间声明相关成员;在声明Person类的同时可以看到它继承于NSObject,这是ObjC的基类,所有的类最终都继承于这个类(但是需要注意ObjC中的基类或者根类并不只有一个,例如NSProxy也是ObjC的基类),由于这个类在Foundation框架中定义,所以导入了<Foundation/Foundaton.h>(这么描述的意思是导入Foundation框架中的Foundation.h声明文件);
  • .m文件:放属性、方法的具体实现;关键字@implementation用于实现某个类,同时必须以@end结尾,在这两个关键字中间实现具体的属性、方法;由于.m中使用了Person类,所以需要导入声明文件“Person.h”;

成员变量

假设在Person类中包含人员姓名(name)、年龄(age)、民族(nation)、身高(height)四个成员变量,同时姓名和年龄两个成员变量是私有的,身高是公开的,民族则限制为只有子类可以访问。

#import <Foundation/Foundation.h>//由于使用了NSObject,所以导入此头文件

//NSObject是基类,Person实现了NSObject
@interface Person : NSObject{
    /*成员变量必须包含在大括号中
     *注意成员变量不声明任何关键字的话是默认可访问性@Protected
     *注意在ObjC中不管是自定义的类还是系统类对象都必须是一个指针,例如下面的_name
     */
    @private
    NSString *_name;//在ObjC中推荐成员变量名以_开头
    int _age;
    @protected
    NSString *_nation;
    @public
    float height;
}

@end

成员变量定义在.h文件中,同时必须定义在类后面的{}内。成员的可访问性通过下面三个关键字声明:

  • @private 私有成员,只有当前类可以访问;
  • @protected 受保护成员,只有当前类或子类可以访问(如果没有添加任何修饰则默认为@protected);
  • @public 公共成员,所有类均可访问;

在ObjC中可访问性修饰符除了这三种,还有一个@package不太常用,它类似于C#中的internal在框架内是公共的,但是框架外是私有的(也就是只能在一个框架内可以访问)。那么既然身高是公共的,外界怎么访问呢?

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p=[Person alloc];
        p=[p init];
        //上面两句代码可以直接写成:Person *p=[[Person alloc] init];
        //还可以写成:Person *p=[Person new];

        p->height=1.72;
        NSLog(@"height=%.2f",p->height);//结果:height=1.72
    }
    return 0;
}

这里需要注意几点:

  • ObjC中所有的对象类型的变量都必须加上“*”,在ObjC中对象其实就是一个指针(例如之前看到的NSString也是如此,但是基本类型不用加”*”);
  • ObjC中使用[]进行方法调用,在ObjC中方法调用的本质就是给这个对象或类发送一个消息;
  • 在ObjC中类的实例化需要两个步骤:分配内存、初始化;
  • 类的初始化调用了父类的init方法,如果使用默认初始化方法进行初始化(没有参数),内存分配和初始化可以简写成[Person new];
  • 公共成员的调用使用“->”操作符;

方法和属性

既然有了上面成员变量,假设现在需要一个对象方法去设置用户姓名,还需一个类方法打印一些信息。

在ObjC中方法分为静态方法和动态方法两种,动态方法就是对象的方法,静态方法就是类方法,这一点跟其他高级语言没有区别。在ObjC中使用“-”定义动态方法,使用“+”定义静态方法。如果一个方法在.h中有声明则该方法是公共方法,如果没有在.h中声明直接在.m中定义则该方法是私有方法,外部无法访问。

person.h

#import <Foundation/Foundation.h>//由于使用了NSObject,所以导入此头文件

//NSObject是基类,Person实现了NSObject
@interface Person : NSObject{
    /*成员变量必须包含在大括号中
     *注意成员变量不声明任何关键字的话是@Protected,其他还有@Private和@Public
     *注意在ObjC中不管是自定义的类还是系统类对象都必须是一个指针,例如下面的_name
     */
    @private
    NSString *_name;//在ObjC中推荐变量名以_开头
    int _age;
    @protected
    NSString *_nation;
    @public
    float height;
}

//声明一个动态方法,没有返回值
-(void)setName:(NSString *)name;
//声明一个静态方法,没有返回值
+(void)showMessage:(NSString *)info;

@end

Person.m

#import "Person.h"

@implementation Person

//实现一个动态方法
-(void)setName:(NSString *)name{
    _name=name;
}

//实现一个静态方法
+(void)showMessage:(NSString *)info{
    NSLog(@"%@",info);
}
@end

在ObjC中方法的参数类型、返回值类型需要放到()中,而且参数前必须使用冒号,并且此时冒号是方法名的一部分。当然,上面的方法只有一个参数,假设现在有一个方法可以同时设置年龄和籍贯,可以写成如下形式:

-(void)setAge:(int)age andHeight:(NSString *)nation{
    _age=age;
    _nation=nation;
}

其中andHeight可以省略不写,当然为了保证方法名更有意义建议书写时加上。

大家都知道在其他语言中还会经常提到属性的概念,通常一个成员的访问不会直接通过成员变量而是通过属性暴漏给外界。在ObjC中属性的实现方式其实类似于Java中属性定义,通过对应的setter和getter方法进行实现。没错,上面setName其实就是属性的setter方法,但是在ObjC中gettter方法通常使用变量名,而不加“get”。下面就看一下年龄属性的实现

Person.h

#import <Foundation/Foundation.h>//由于使用了NSObject,所以导入此头文件

//NSObject是基类,Person实现了NSObject
@interface Person : NSObject{
    /*成员变量必须包含在大括号中
     *注意成员变量不声明任何关键字的话是@Protected,其他还有@Private和@Public
     *注意在ObjC中不管是自定义的类还是系统类对象都必须是一个指针,例如下面的_name
     */
    @private
    NSString *_name;//在ObjC中推荐变量名以_开头
    int _age;
    @protected
    NSString *_nation;
    @public
    float height;
}

//声明一个动态方法,没有返回值
-(void)setName:(NSString *)name;
//声明一个静态方法,没有返回值
+(void)showMessage:(NSString *)info;

//声明age的setter、getter方法
-(int)age;
-(void)setAge:(int)age;

@end

Person.m

#import "Person.h"

@implementation Person

//实现一个动态方法
-(void)setName:(NSString *)name{
    _name=name;
}

//私有方法
-(void)setAge:(int)age andHeight:(NSString *)nation{
    _age=age;
    _nation=nation;
}

//实现一个静态方法
+(void)showMessage:(NSString *)info{
    NSLog(@"%@",info);
}

//实现age的setter、getter方法
-(int)age{
    return _age;
}
-(void)setAge:(int)age{
    _age=age;
}
@en
// 这里是具体调用#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p=[Person alloc];
        p=[p init];
        //上面两句代码可以直接写成:Person *p=[[Person alloc] init];
        //还可以写成:Person *p=[Person new];

        //成员变量调用
        p->height=1.72;
        NSLog(@"height=%.2f",p->height);//结果:height=1.72

        //方法调用
        [p setName:@"Kenshin"];

        //属性调用
        p.age=28; //等价于:[p setAge:28];
        int age=p.age;//等价于:age=[p age];
        NSLog(@"age=%i",age); //结果:age=28

    }
    return 0;
}

我们可以看到p.age的调用方式,是不是类似于C#、Java中属性的调用方式,这就是ObjC中的点语法。其实这种方式调用的本质还是调用对应的方法进行处理,这么做的目的只是为了开发人员书写方便而已(这就是语法糖的目的)。至于p.age是调用get方法还是调用set方法完全取决于当前操作是赋值操作还是读取操作。

通过上面的程序我们可以看到如果要定义一个属性,首先需要在.h中声明其次还要在.m中实现,而定义属性的代码基本都是类似的。

self关键字

在C#、Java中都有一个关键字this用于表示当前对象,其实在ObjC中也有一个类似的关键字self,只是self不仅可以表示当前对象还可以表示类本身,也就是说它既可以用在静态方法中又可以用在动态方法中。

Perosn.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property NSString *name;
@property int age;

-(void)setName:(NSString *)name andAge:(int)age;

+(void)showMessage;
@end

Person.m

#import "Person.h"

@implementation Person
-(void)setName:(NSString *)name andAge:(int)age{
//    _name=name;
//    _age=age;
    self.name=name;
    self.age=age;
}

+(void)printInfo{
    NSLog(@"Hello,World!");
}

+(void)showMessage{
    [self printInfo];
}
@end

main.m

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {

    Person *p=[[Person alloc]init];
    [p setName:@"Kenshin" andAge:28];
    [Person showMessage];

    return 0;
}

在上面代码中可以看到setName: andAge:方法是一个动态方法,此时self就代表调用对象;而在showMessage方法中self调用了类的静态方法printInfo,此时self代表调用的类;因此可以总结出在ObjC中self就代表当前方法的调用者。

时间: 05-08

黑马程序员---Objective-C基础学习---类、对象、方法相关知识笔记的相关文章

【黑马程序员】-Java基础学习-多线程

------- android培训.java培训.期待与您交流! --------- 首先讲一下进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程. 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小. 线程和进程一样分为五个阶段:创建.就绪.运行.阻塞.终止. 多进程是指操作系统能同时运行多个任务(程序). 多线程是指在同一程序中有多个顺序流在执行.

【黑马程序员】-Java基础学习-输出一个空心菱形

1 package test; 2 3 /** 4 * 内容是输出一个空心菱形 5 * @author 瞎猫碰到死老虎 6 * 7 */ 8 9 public class linXing { 10 11 public static void main(String[] args) { 12 int n=15; 13 lingxing(n); 14 15 } 16 17 //输出一个n行的菱形 18 public static void lingxing(int n){ 19 //先输出上半部分

黑马程序员—张老师基础加强7-动态代理

代理: 要为已经存在的多个具有相同接口的目标类的各个方法增加一些系统功能. 例如:异常处理,日志和计算方法的运行时间,事物管理等,怎么做 如 在运行前后增加计算时间的方法.show(){ sop(); } 编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码. 动态代理: 要为系统中的各种接口的类增加代理功能,那需要太多代理类. jvm可以在运行期间动态生成出类的字节码,这种动态生成的类往往被调用作代理类, 即动态代理类. jvm生成动态类

黑马程序员-张老师基础5-泛型

泛型: 泛型只是提供给编译器.在编译完之后,生产字节码文件时就擦除类型信息,<>泛型就不在了 泛型的术语: 整个Arraylist<E>:称为泛型类型. Arraylist<E>中的E称为类型变量或类型参数 整个Arraylisst<Integer>称为:参数化的类型 Arraylist<Integer>中的Integer称为类型参数的实例. Arraylist<Integer>中的<>是typeof Arraylist称

黑马程序员——Java集合基础知识之Map

Map概念 要同时存储两个元素Key和Value,他们之间有映射关系,每个键不能重复,每个键只能映射到一个值. 当数据之间存在映射关系的时候,考虑使用Map集合. Map常用方法 如果添加的键原来有值,后添加的值会覆盖前面的值,并返回之前的值.put会返回来先添加的值,后添加的值会覆盖原有的值. Map tm =new TreeMap(); tm.put (key, value);//MAP没有add tm.remove (key) ;//去除一个key和对应的value,若不存在key返回nu

黑马程序员——Java集合基础知识之Collection

集合基础知识--Collection Java中集合框架由常用的Collection接口和Map接口组成,而Collection接口又有两个子接口,是List接口和Set接口,常用的集合框架由这三个类组成. List接口的功能方法 List的使用最为简单,创建集合,通过add方法添加元素,get方法获取元素,通过迭代器获取元素.List接口存放的数据无序的,添加速度快,但是查询速度慢,因为查询的时候必须遍历,每次都重头开始,效率较低.常用实现类有ArrayList,LinkedList. Lis

黑马程序员——java多线程基础知识1

多线程 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行.jvm启动的时候会有一个进程就叫做java,exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为主线程.虚拟机至少也有两个线程,一个主线程执行,另一个负

黑马程序员——Java多线程基础知识2

多线程协同 线程间的通讯:我们对资源的操作动作不同,比如说两个卡车一个拉煤一个装煤.但是他们共享了一个资源. 怎么样把这个资源拿出来?怎样把车装满?这个资源当然是一个类,他里面的组成元素就是对象!!现在我们就要有操作对象的思想了,我用对象把这车装满,现在一车装一个对象. 等待唤醒机制: 用的不是sleep是wait.flag标记,这是两人沟通的方式.其实每个标记就要做一次等待或者notify,判断wait,改值notify.线程池.notify唤醒里面的线程,按顺序唤醒.wait和notify必

黑马程序员之Java多线程学习

android培训  java培训 期待与您交流! 这一篇文章主要关于java多线程,主要还是以例子来驱动的.因为讲解多线程的书籍和文章已经很多了,所以我也不好意思多说,呵呵.大家可以去参考一些那些书籍.我这个文章主要关于实际的一些问题.同时也算是我以后复习的资料吧,.呵呵大家多多指教. 同时希望多结交一些技术上的朋友.谢谢. -------------------------------------------------------------------------------------