OC语言基础

2018-03-04  本文已影响0人  恒筠

第一课

1.对象方法和类方法区别

2.函数与方法对比

函数属于整个文件,可以写在文件中的任何位置,包括@implementation...@end中,但写在 @interface...@end会无法识别,函数的声明可以在main函数内部也可以在main函数外部。

3.通过类创建对象

通过类创建对象





第二课

1.对象和方法之间的关系

对象作为方法参数传递是地址传递,因为对象是一个指针变量
在方法内部,可以通过对象形参,访问该对象的成员变量(如果该对象的该成员变量的访问权限是public的)
在方法内部,可以通过对象形参,调用该对象上的方法(给这个对象发送消息)

2.xcode项目模版的修改

3.修改类的头部信息

4.NSString的基本使用

// C语言中的字符串不是对象
    char *name1 = "lnj";
    char name2[] = "lmj";
    
    // OC中的字符串是一个对象
    // 正是因为OC中的字符串是一个对象, 所以它就具备了很多功能
    NSString *str = @"lk";
    
    Iphone *p = [Iphone new];
    // 注意: 输出C语言的字符串使用%s
    //      输出OC的字符串使用%@,  %@就专门用于输出对象类型的
//    NSLog(@"content = %s", [p loadMessage]);
    NSLog(@"content = %@", [p loadMessage]);

第三课

1.self关键字

+ (void)carameWithFlahlightStatus:(FlahlightStatus)status
{
    if (status == kFlahlightStatusOpen) {
//        [Iphone openFlahlight];
        ** // 其实在类方法中调用类方法除了可以使用类名调用以外, 还可以使用self来调用**
        [self openFlahlight];
    }else
    {
//        [Iphone closeFlahlight];
        // self == Iphone
        [self closeFlahlight];
    }
    NSLog(@"拍照");
    
}

2.多态

多态: 事物的多种表现形态
动态类型: 在编译的时候编译器只会检查当前类型对应的类中有没有需要调用的方法
在运行时,系统会自动判断a1的真实类型

  Animal *a1 = [Dog new];
    [a1 eat];

注意点: 在多态中, 如果想调用子类特有的方法必须强制类型转换为子类才能调用

3.description关键字

第四课

1.OC中的私有方法

OC中的私有变量

@implementation Dog
{
    @public
    int _age;
}
@end

2.OC中的私有方法

3.id类型

```
/// Represents an instance of a class.
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;
```


```
 id obj = [C at new];
 [obj eat]; // 不用强制类型转换

 [obj test]; //可以调用私有方法
```
id obj = [Student new];
    /*
    if ([obj isKindOfClass:[Student class]]) {
        // isKindOfClass , 判断指定的对象是否是某一个类, 或者是某一个类的子类
        [obj eat];
    }
     */
   
    if ([obj isMemberOfClass:[Student class]]) {
        // isMemberOfClass : 判断指定的对象是否是当前指定的类的实例
        [obj eat];
    }

4.构造方法

重写init方法

- (id)init {
    self = [super init];
    if (self) {
        // Initialize self.
    }
    return self;
}
- (id)init {
    if (self = [super init]) {
        // Initialize self.
    }
    return self;
}

构造方法使用注意

5.自定义类工厂方法


@interface Person : NSObject
+ (id)person;
@end

@implementation Person
+ (id)person
{
//   return  [[Person alloc]init];
//     谁调用这个方法,self就代表谁
//    注意:以后写类方法创建初始化对象,写self不要直接写类名
    return  [[self alloc]init];
}
@end

@interface Student : Person
@property NSString *name;
@end

@implementation Student
@end

int main(int argc, const char * argv[])
{
    Student *stu = [Student person];// [[Student alloc] init]
    [stu setName:@"lnj"];
}

6.类的本质

7.类的启动过程

+load方法

```
@implementation Person

+ (void)load
{
    NSLog(@"%s", __func__);
}
@end

@implementation Student : Person

+ (void)load
{
    NSLog(@"%s", __func__);
}
@end

输出结果:
+[Person load]
+[Student load]
```

+initialize

8.property的增强

9.SEL类型

```
    SEL sel = @selector(setAge:);
    Person *p = [Person new];
    // 判断p对象中有没有实现-号开头的setAge:方法
    // 如果P对象实现了setAge:方法那么就会返回YES
    // 如果P对象没有实现setAge:方法那么就会返回NO
    BOOL flag = [p respondsToSelector:sel];
    NSLog(@"flag = %i", flag);
```
```
   SEL sel1 = @selector(signalWithNumber:);
    // withObject: 需要传递的参数
    // 注意: 如果通过performSelector调用有参数的方法, 那么参数必须是对象类型,
    // 也就是说方法的形参必须接受的是一个对象, 因为withObject只能传递一个对象
    [p performSelector:sel1 withObject:@"13838383438"];
    
    SEL sel2 = @selector(setAge:);
    [p performSelector:sel2 withObject:@(5)];
    NSLog(@"age = %i", p.age);
    
    // 注意:performSelector最多只能传递2个参数
```
```
/    Car *c = [Car new];
//    SEL sel = @selector(run);
//    
//    Person *p = [Person new];
//    [p makeObject:c andSel:sel];
```

第五课

1.内存管理

2.堆和栈

3.dealloc方法

4.野指针/空指针

5.多对象内存管理原则

在mrc环境下

// 当A对象想使用B对象一定要对B对象进行一次retain, 这样才能保证A对象存在B对象就存在, 也就是说这样才能保证无论在什么时候在A对象中都可以使用B对象
// 当A对象释放的时候, 一定要对B对应进行一次release, 这样才能保证A对象释放了, B对应也会随之释放, 避免内存泄露
// 总结一句话: 有增就有减


换房了, 如果set方法中没有release旧值, 就会内存泄露
- (void)setRoom:(Room *)room // room = r
{
    // 只有房间不同才需用release和retain
    if (_room != room) {// 0ffe1 != 0ffe1
        
        // 将以前的房间释放掉 -1
        [_room release];
        
        /*
        // 对房间的引用计数器+1
        [room retain];
        
        _room = room;
         */
        // retain不仅仅会对引用计数器+1, 而且还会返回当前对象
        _room = [room retain];
    }
}

- (void)dealloc
{
    // 人释放了, 那么房间也需要释放
    [_room release];
    NSLog(@"%s", __func__);
    [super dealloc];
}

6.class和#import

作用上的区别

7.property修饰符

/*
retain: 就会自动帮我们生成getter/setter方法内存管理的代码
assign: 不会帮我们生成set方法内存管理的代码, 仅仅只会生成普通的getter/setter方法, 默认什么都不写就是assign
*/
@property(nonatomic, retain) Room *room;

第六课

1.autorelease

    ```
    @autoreleasepool { // 栈底自动释放池
      @autoreleasepool {
          @autoreleasepool { // 栈顶自动释放池
              Person *p = [[[Person alloc] init] autorelease];
          }
          Person *p = [[[Person alloc] init] autorelease];
      }
    }
    ```

2.ARC(Automatic Reference Counting)

ARC的判断原则

注意:当使用ARC的时候,暂时忘记“引用计数器”,因为判断标准变了。

ARC下多对象内存管理

```
@interface Person : NSObject

// MRC写法
//@property (nonatomic, retain) Dog *dog;

// ARC写法
@property (nonatomic, strong) Dog *dog;

@end
```
@interface Person : NSObject

//@property (nonatomic, retain) Dog *dog;
@property (nonatomic, strong) Dog *dog;

@end

@interface Dog : NSObject

// 错误写法, 循环引用会导致内存泄露
//@property (nonatomic, strong) Person *owner;

// 正确写法, 当如果保存对象建议使用weak
//@property (nonatomic, assign) Person *owner;
@property (nonatomic, weak) Person *owner;
@end

3.ARC模式下如何兼容非ARC的类

4.Category

5.类扩展(Class Extension)

6.Block

Block的定义格式

//定义的格式类似c语言中指向函数的指针

返回值类型 (^block变量名)(形参列表) = ^(形参列表) {

};

7.Block的注意事项

第七课

1.protocol

@protocol SportProtocol <NSObject> // 基协议

- (void)playFootball;
- (void)playBasketball;
@end
* @required:这个方法必须要实现(若不实现,编译器会发出警告)
* @optional:这个方法不一定要实现

2.代理设计模式

3.NSString

如果是通过字符串常量创建,那么字符串对象存储在常量区中
如果是通过alloc initWithFormat/stringWithFormat创建,那么字符串对象存储在堆区中
而且需要注意:
不同的平台存储的方式也不一样,如果是Mac平台系统会自动对字符串对象进行优化,但是如果是iOS平台就是两个对象
不同的编译器存储的方式也不一样,如果是Xcode6以下并且是在iOS平台,那么每次alloc都会创建一个新的对象,如果是在Xcode6以上那么alloc多次指向同一块存储空间

```
typedef struct _NSRange {
    NSUInteger location;
    NSUInteger length;
} NSRange;
// NSUInteger的定义
typedef unsigned int NSUInteger;
```

```
NSRange range = NSMakeRange(7, 3);
```

4.NSMutableString

5.NSArray

```
    NSArray *arr = [NSArray arrayWithObjects:@"lnj", nil ,@"lmj",@"jjj", nil];
    NSLog(@"%@", arr);
输出结果:
(
    lnj
)
```
// 创建一个空的数组
    NSMutableArray *arrM = [NSMutableArray array];
    NSLog(@"%@", arrM);
    // 如何添加
    [arrM addObject:@"lnj"];
    // 将指定数组中的元素都取出来, 放到arrM中
    // 并不是将整个数组作为一个元素添加到arrM中
    [arrM addObjectsFromArray:@[@"lmj", @"jjj"]];
    // 注意: 以下是将整个数组作为一个元素添加
//    [arrM addObject:@[@"lmj", @"jjj"]];
    NSLog(@"%@", arrM);

第八课

1.NSDictionary

    ```
    @[@"Jack", @"Rose"] (返回是不可变数组)
    
    ```
    
* NSDictionary的用法 +创建

     ```
           
        NSDictionary *dict = @{key:value};
        NSDictionary *dict = @{@"name": @"lnj"};
        NSLog(@"%@", dict[@"name"]);
            
        NSDictionary *dict = @{@"name":@"lnj", @"age":@"30", @"height":@"1.75"};

        @{ @"name" : @"Jack", @"phone" : @"10086" } (返回是不可变字典)
   
   
* 字典的遍历

        
    ```
    for (int i = 0; i < dict.count; ++i) {
    // 获取字典中所有的key
    NSArray *keys = [dict allKeys];
    // 取出当前位置对应的key

// NSLog(@"%@", keys[i]);
NSString *key = keys[i];
NSString *value = dict[key];
NSLog(@"key = %@, value = %@", key, value);
}

    ```
    
    * **字典的遍历(2)(常用)**

    
    ```
    //如何通过forin遍历字典, 会将所有的key赋值给前面的obj

for (NSString *key in dict) {
NSLog(@"%@", key);
NSString *value = dict[key];
NSLog(@"key = %@, value = %@", key, value);
}
```

    * 字典的遍历(3)
   [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        NSLog(@"key = %@, value = %@", key, obj);
    }];

注意:

2.NSNumber

    ```
    + (NSNumber *)numberWithInt:(int)value;
    + (NSNumber *)numberWithDouble:(double)value;
    + (NSNumber *)numberWithBool:(BOOL)value;
    
    ```   
* 现在


    ```
       @10;
       @10.5;
       @YES;
       @(num);
    ```
    
* 基本数据类型转换对象类型简写
    * 注意: 如果传入的是变量那么必须在@后面写上(), 如果传入的常量, 那么@后面的()可以省略

        ```    
            NSNumber *temp = @(number);
            NSNumber *temp  =@10.10;
            NSLog(@"%@", temp);
        ```

3.NSValue

```

// 1.利用NSValue包装常用的结构体
    /*
    CGPoint point = NSMakePoint(10, 20);
    NSValue *value = [NSValue valueWithPoint:point];
    NSArray *arr = @[value];
    NSLog(@"%@", arr);
     */
    
    // 2.利用NSValue包装自定义的结构体
    typedef struct{
        int age;
        char *name;
        double height;
    }Person;
    
    Person p = {30, "lnj", 1.75};
    // valueWithBytes: 接收一个指针, 需要传递需要包装的结构体的变量的地址
    // objCType: 需要传递需要包装的数据类型
    NSValue *pValue = [NSValue valueWithBytes:&p objCType:@encode(Person)];
    NSArray *arr = @[pValue];
    NSLog(@"%@", arr);
    // 从NSValue中取出自定义的结构体变量
    Person res;
    [pValue getValue:&res];
    NSLog(@"age = %i, name = %s, height = %f", res.age, res.name, res.height);

```

4.NSDate

```
NSCalendar *calendar = [NSCalendar currentCalendar];
```
// 创建一个时间格式化对象
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    // 告诉时间格式化对象, 按照什么样的格式来格式化时间
    // yyyy 年
    // MM 月
    // dd 日
    // HH 24小时  hh 12小时
    // mm 分钟
    // ss 秒钟
    // Z 时区
- (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDate:(NSDate *)date;

5.NSFileManager

// createDirectoryAtPath: 告诉系统文件夹需要创建到什么位置
    // withIntermediateDirectories: 如果指定的文件中有一些文件夹不存在, 是否自动创建不存在的文件夹
    // attributes: 指定创建出来的文件夹的属性
    // error: 是否创建成功, 如果失败会给传入的参数赋值
    // 注意: 该方法只能用于创建文件夹, 不能用于创建文件
     BOOL flag = [manager createDirectoryAtPath:@"/Users/chenhengjun/Desktop/Beginlnj" withIntermediateDirectories:YES attributes:nil error:nil];
    NSLog(@"%i", flag);

判断一个文件或者文件夹是否存在

 BOOL flag = [manager fileExistsAtPath:@"/Users/chenhengjun/Desktop/Begin"];
NSLog(@"flag = %i", flag);

判断一个文件是否存在, 并且判断它是否是一个文件夹

BOOL dir = NO;
//    BOOL flag = [manager fileExistsAtPath:@"/Users/chenhengjun/Desktop/Begin" isDirectory:&dir];
//    NSLog(@"flag = %i, dir = %i", flag, dir);

获取文件或文件夹的属性

注意:contentsOfDirectoryAtPath方法有一个弊端, 只能获取当前文件夹下所有的文件, 不能获取子文件夹下面的文件
//    NSArray *res = [manager contentsOfDirectoryAtPath:@"/Users/chenhengjun/Desktop/Begin" error:nil];
//    NSLog(@"res = %@", res);
 NSArray *res = [manager subpathsAtPath:@"/Users/chenhengjun/Desktop/Begin"];
////    NSArray *res = [manager subpathsOfDirectoryAtPath:@"/Users/chenhengjun/Desktop/Begin" error:nil];
//    NSLog(@"res = %@", res);

创建文件

createFileAtPath: 指定文件创建出来的位置
    // contents : 文件中的内容
    // attributes: 创建出来的文件的属性
    
    // NSData : 二进制数据
    // 注意: 该方法只能用于创建文件, 不能用于创建文件夹
//    NSString *str = @"江哥真帅";
//    NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
//    [manager createFileAtPath:@"/Users/xiaomage/Desktop/abc.txt" contents:data attributes:nil];

6.Copy

/ 如果是通过不可变对象调用了copy方法, 那么不会生成一个新的对象
// 原因: 因为原来的对象是不能修改的, 拷贝出来的对象也是不能修改的
// 既然两个都不能修改, 所以永远不能影响到另外一个对象, 那么已经符合需求
// 所以: OC为了对内存进行优化, 就不会生成一个新的对象
NSString *srcStr = @"lnj";
NSString *copyStr = [srcStr copy];
NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);
    
/*
正是因为调用copy方法有时候会生成一个新的对象, 有时候不会生成一个新的对象
所以: 如果没有生成新的对象, 我们称之为浅拷贝, 本质就是指针拷贝
     如果生成了新的对象, 我们称之为深拷贝, 本质就是会创建一个新的对象
*/

7.单例

+ (instancetype)shareTools
{
    Tools *instance = [[self alloc] init];
    return instance;
}

static Tools *_instance = nil;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone:zone] init];
    });
    return _instance;
}


- (id)copyWithZone:(NSZone *)zone{

    return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}

// MRC
- (oneway void)release
{

}

- (instancetype)retain
{
    return _instance;
}

- (NSUInteger)retainCount
{
    return  MAXFLOAT;
}

宏定义重构单例

#define interfaceSingleton(name)  +(instancetype)share##name


#if __has_feature(objc_arc)
// ARC
#define implementationSingleton(name)  \
+ (instancetype)share##name \
{ \
name *instance = [[self alloc] init]; \
return instance; \
} \
static name *_instance = nil; \
+ (instancetype)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[super allocWithZone:zone] init]; \
}); \
return _instance; \
} \
- (id)copyWithZone:(NSZone *)zone{ \
return _instance; \
} \
- (id)mutableCopyWithZone:(NSZone *)zone \
{ \
return _instance; \
}
#else
// MRC

#define implementationSingleton(name)  \
+ (instancetype)share##name \
{ \
name *instance = [[self alloc] init]; \
return instance; \
} \
static name *_instance = nil; \
+ (instancetype)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[super allocWithZone:zone] init]; \
}); \
return _instance; \
} \
- (id)copyWithZone:(NSZone *)zone{ \
return _instance; \
} \
- (id)mutableCopyWithZone:(NSZone *)zone \
{ \
return _instance; \
} \
- (oneway void)release \
{ \
} \
- (instancetype)retain \
{ \
return _instance; \
} \
- (NSUInteger)retainCount \
{ \
return  MAXFLOAT; \
}
#endif

上一篇下一篇

猜你喜欢

热点阅读