ARC下内存泄露的一些情况

  1. 循环引用
    A有个属性参照B,B有个属性参照A,如果都是strong参照的话,两个对象都无法释放。

这种问题常发生于把delegate声明为strong属性了。

上例中,解决办法是把SampleClass 的delegate属性的strong改为assing即可。

  1. 死循环

    如果某个ViewController中有无限循环,也会导致即使ViewController对应的view关掉了,ViewController也不能被释放。

这种问题常发生于animation处理。

CATransition *transition = [CATransition animation];

transition.duration = 0.5;

tansition.repeatCount = HUGE_VALL;

[self.view.layer addAnimation:transition forKey:”myAnimation”];

上例中,animation重复次数设成HUGE_VALL,一个很大的数值,基本上等于无限循环了。

解决办法是,在ViewController关掉的时候,停止这个animation。

参照资料: http://www.aichengxu.com/view/30206

  1. block的循环引用:

这个例子的问题就在于在使用 block 的过程中形成了循环引用:self 持有 networkFetecher;networkFetecher 持有 block;block 持有 self。三者形成循环引用,内存泄露。

4.performSelector 系列
performSelector 顾名思义即在运行时执行一个 selector,最简单的方法如下

  • (id)performSelector:(SEL)selector;

但 performSelector 相比直接调用更加灵活

SEL selector;
if (/ some condition /) {
selector = @selector(newObject);
} else if (/ some other condition /) {
selector = @selector(copy);
} else {
selector = @selector(someProperty);
}
id ret = [object performSelector:selector];

这段代码就相当于在动态之上再动态绑定。在 ARC 下编译这段代码,编译器会发出警告

正是由于动态,编译器不知道即将调用的 selector 是什么,不了解方法签名和返回值,甚至是否有返回值都不懂,所以编译器无法用 ARC 的内存管理规则来判断返回值是否应该释放。因此,ARC 采用了比较谨慎的做法,不添加释放操作,即在方法返回对象时就可能将其持有,从而可能导致内存泄露。

  1. 在使用 NSTimer addtarget 时,为了防止 target 被释放而导致的程序异常,timer 会持有 target,所以这也是一处内存泄露的隐患。

6.try…catch

详细参照:https://www.zybuluo.com/MicroCai/note/67734
觉得总结的不错。

iOS的多线程

在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势必影响用户体验。

在没有顺序要求的情况下使用多线程既能解决线程阻塞又能充分利用多核处理器运行能力。

在 iOS 中其实目前有 4 套多线程方案,他们分别是:

Pthreads

NSThread

NSOperation & NSOperationQueue

GCD

Pthreads简单地说,这是一套在很多操作系统上都通用的多线程API,所以移植性很强(然并卵),当然在 iOS 中也是可以的。不过这是基于 c语言 的框架。想要自己实现一套多线程方案,从底层开始定制,那么可以去搜一下相关资料。

后三种方式是随着iOS的发展逐渐引入的,所以相比而言后者比前者更加简单易用,并且GCD也是目前苹果官方比较推荐的方式(它充分利用了多核处理器的运算性能)

接下来简单说下它们的创建:

1.Pthreads: (大多数情况下用不到)

  • (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event {
    pthread_t thread;
    //创建一个线程并自动执行
    pthread_create(&thread, NULL, start, NULL);
    }

void start(void data) {
NSLog(@”%@”, [NSThread currentThread]);

return NULL;

}

2.NSThread
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];

// 启动
[thread start];

// 取消
[thread cancel];

// 创建并自动启动
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];

更多方法大家可以去类的定义里去看。

  1. GCD

    // 后台执行:
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    // something
    });

    // 主线程执行:
    dispatch_async(dispatch_get_main_queue(), ^{
    // something
    });

    // 一次性执行:
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    // code to be executed once
    });

    // 延迟2秒执行:
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // code to be executed on the main queue after delay
    });

    // 自定义dispatch_queue_t
    dispatch_queue_t urls_queue = dispatch_queue_create(“blog.devtang.com”, NULL);
    dispatch_async(urls_queue, ^{
       // your code
    });
    dispatch_release(urls_queue);

    // 合并汇总结果
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
    // 并行执行的线程一
    });
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
    // 并行执行的线程二
    });
    dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
    // 汇总结果
    });

4.NSOperation & NSOperationQueue

NSOperation *operation = [[NSOperation alloc] init];

[operation start];
NSOperation调用start方法即可开始执行操作,NSOperation对象默认按同步方式执行,也就是在调用start方法的那个线程中直接执行。NSOperation对象的isConcurrent方法会告诉我们这个操作相对于调用start方法的线程,是同步还是异步执行。isConcurrent方法默认返回NO,表示操作与调用线程同步执行.

start方法用来启动一个Operation任务。同时,Operation提供一个main方法,你的所有任务都应该在main中进行处理。默认的start方法中会先做出一些异常判断然后直接调用main方法。如果需要自定义一个NSOperation必须重载main方法来执行你所想要执行的任务。

-(void)main {
@try {
// Do some work.
}
@catch(…) {
// Exception handle.
}
}
@end

如果你把NSOperation交给队列去维护,只需要实现main方法就行了,但是你如果想要手动去控制这个线程(启动。。。),需要自己调用start方法,但是这样是不安全的,因为若 没有获得充分资源,而此时你调用start方法,就会抛出异常。这是官方文档里面说的。

[operation cancel];

至于star和main的区别,到论坛里看到有这样说的:实现main方法, 线程串行执行; 实现start方法, 线程并发执行.

NSOperationQueue queue = [NSOperationQueue new];
NSInvocationOperation
operation = [[NSInvocationOperation alloc];
initWithTarget:self
selector:@selector(doWork:)
object:someObject];
[queue addObject:operation];

还有关于

串行是排成一列,像糖葫芦。串行是一次只能执行一个任务,并行是排成一行一次能执行多个任务

并行是CPU的多核芯同时执行多个任务, 并发是单核CPU交替执行两个任务

这里再加几个名词解释:

进程:一个可执行的程序

任务:一块可执行的代码

线程:指的是一个独立的代码执行路径,线程是代码执行路径的最小分支

同步 和 串行的区别 ?
异步 和 并行的区别 ?
关于这个问题我暂时没有想到答案,只是觉得它们在某些地方类似,但是完全是两个不同的概念。

关于并发 并行 同步 异步 多线程的区别:
http://blog.csdn.net/cqkxboy168/article/details/9026205

捎带提一下 线程安全和非线程安全

线程安全就是在多线程环境下也不会出现数据不一致,而非线程安全就有肯能出现数据不一致
线程安全的类由于要确保线程安全增加了一定的开销,所以在单线程环境中效率没非线程安全的类效率高

原子和非原子属性的选择
nonatomic和atomic对比
atomic:线程安全,需要消耗大量的资源
nonatomic:非线程安全,适合内存小的移动设备

iOS开发的建议
所有属性都声明为nonatomic
尽量避免多线程抢夺同一块资源
尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等等问题,所以我们需要给线程加一个线程锁。线程锁的使用格式是:@synchronized(锁对象) { // 需要锁定的代码 }锁定1份代码只用1把锁,用多把锁是无效的。

关于锁:http://blog.csdn.net/likendsl/article/details/8568961

runloop运行循环精致介绍

运行循环是由类NSRunLoop表示的,一个线程一次只能执行一个任务,执行完成后线程就会退出。

有些线程可以让操作系统唤醒睡眠的线程以管理到来的事件,而运行循环则是这些线程的基础组件。运行循环是这样一种循环,可以在一个周期内调度任务并处理到来的事件。如果我们需要一个runloop机制,让线程能随时处理事件但并不退出.iOS应用中的每个线程最多只有一个运行循环。对于主线程来说,运行循环会为你开始,在应用委托的applicationDidFinishLaunchingWithOptions:方法调用后就可以访问了。不过辅助线程必须显式运行自己的运行循环。

在辅助线程中开始运行循环之前,你至少要添加一个输入源或定时器;否则,运行循环就会立刻退出。

运行循环向开发者提供了与线程交互的能力,不过有时并不是必需的。

比如,没有任何其他交互而处理大数据集的线程可能就不会开始运行循环。然而,
如果辅助线程与网络交互,就需要开启运行循环。‘

运行循环会从两类源中接收事件:输入源与定时器。

输入源(通常是基于端口的或是自定义的)会异步向应用发送事件。这两类源的主要差别在于内核会自动发出基于端口的源信号,而自定义源就需要从不同的线程中手动发出。可以通过实现与CFRunLoopSourceRef相关的几个回调函数来创建自定义输入源。

定时器会生成基于时间的通知,它为应用(特别是线程)提供了一种机制,以在未来的某个时间执行某个具体任务。定时器事件是同步发出的,并且与特定的模式有关,后面将会对此进行介绍。如果这个特定的模式当前并没有被监控,那么事件就会被忽略掉,线程也不会收到通知,直到运行循环”运行”在相应的模式下为止。

可以配置定时器以触发一次或者重复触发。重新调度是基于调度的触发时间而不是实际的触发时间。如果定时器触发,同时运行循环正在执行一个应用处理器方法,那么它会等待,直到下一次通过运行循环来调用定时器处理器为止,这一般是通过设定@selector()实现的。如果触发处理器被推迟到了下一次调用发送的那个点,那么定时器只会触发一个事件,之前延迟的事件则会被压制住。

运行循环也可以有观察者,他们不会被监控,这为对象提供了一种方式,使之可以在运行循环执行过程中的某个活动发送时收到回调。这些活动包括进入或退出运行循环、运行循环睡眠或唤醒、运行循环处理输入源或定时器之前等。CFRunloopActivity 枚举的文档中对此有说明。观察者可以配置成触发一次,这样当触发后就会将其删除,也可以配置成重复的,要想添加运行循环观察者,请使用CoreFoundation函数CFRunloopObserverRef().

运行循环模式

每次通过运行循环都是在你所指定的模式下的一次运行。运行循环模式是由操作系统所用的一种约定,用于过滤监控的源并发布事件,比如调用委托方法等,模式包含了应该监控的输入源与定时器,以及当前运行循环事件发生时应该通知的观察者。

在iOS中有两个预定义的运行循环模式。NSDefaultRunLoopMode(Core Foundation中的kCFRunLoopDefaultmode)是系统默认的,在开始运行循环以及配置输入源时通常会使用它。NSRunLoopCommonModes(core foundation中的kCFRunloopCommonModes)是个可配置的模式集合。通过在输入源实例上调用 scheduleInRunLoop:forMode:等方法,讲NSRunLoopCommonModes赋给输入源会将其与当前组中的所有模式关联起来。

虽然NSRunLoopCommonModes是可配置的,但这是个底层过程,需要调用Core Foundation函数CFRunloopAddCommonMode().这会自动注册输入源、定时器与新模式的观察者,而不必手工讲其添加到每个新模式中。可以通过制定自定义字符串(如@“customRunLoopMode”) 来定义自定义运行循环模式。想要提高自定义运行循环的效率,你至少需要添加一个输入源、定时器或是观察者。

为什么要有runloop呢?群友:因为手机是个消耗品 主要是电 当没有操作的时候手机需要休眠进行良性循环 也可以理解成一个触发器 你预制的事件在没有被触发的时候就会进入低消耗模式

有不同意见的或者对文章有疑问的请评论,我会及时回复,一起交流探讨。

另外可以加入我们的群:328218600

深入理解@property

看文章之前,我们先思考下,@property 为什么会存在,它的意义在于什么?我们普通定义的变量和用@Property定义的有什么区别?如果只是作用域的问题,那么跟public的成员变量有何区别?以及@Property后面括号里的各个关键字的作用。希望看完此文能够解开这些迷惑,更好的理解@Property和对它更好的运用。

首先我们先来看下什么是@property ,Objective-C语言关键词,与@synthesize配对使用。xcode4.5以及以后的版本,@synthesize可以省略。

声明property的语法为:@property (参数1,参数2) 类型 名字;
如:
@property(nonatomic,retain) UIWindow *window;

其中括号里的参数主要分为三类:
读写属性:
(readwrite/readonly/setter = /getter = )

setter语意:
(assign/retain/copy)

原子性:
(atomicity/nonatomic)

各参数意义如下:
readwrite
产生setter\getter方法

readonly
只产生简单的getter,没有setter, 默认的读写属性.

setter =
指定生成setter方法的名字

getter =
指定生成getter方法的名字

assign
默认类型,setter方法直接赋值,而不进行retain操作, 适用于基本数据类型, 对对象类型, 不会发生引用计数变化.

retain
setter方法对参数进行release旧值,再retain新值。

copy
setter方法进行Copy操作,与retain一样,使用copy:对NSString类型 关于copy以后会写一篇文章专门说说

atomic
保证多线程访问下的安全, 但浪费系统资源, 原子性控制的默认设置.

nonatomic
禁止多线程,变量保护,提高性能
指出访问器不是原子操作,而默认地,访问器是原子操作。这也就是说,在多线程环境下,解析的访问器提供一个对属性的安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是别的线程也正在对其进行访问。如果你不指定nonatomic,在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了nonatomic,那么访问器只是简单地返回这个值。

还有strong与weak是由ARC新引入的对象变量属性
xcode 4.2(ios sdk4.3和以下版本)和之前的版本使用的是retain和assign,是不支持ARC的。xcode 4.3(ios5和以上版本)之后就有了ARC,并且开始使用
strong与weak
简单讲strong等同retain weak等同于assign。只是根据mrc和arc的时候选择使用。

unsafe_unretained
unsafe_unretained 就是ios5版本以下的 assign ,也就是 unsafe_unretained , weak, assign 三个都是一个样的。 因为 ios5用的是 weak ,那在ios4.3就用不了,如果你将 weak 修改为 unsafe_unretained ,那就可以用了。说到底就是iOS 5之前的系统用该属性代替 weak 来使用。

关于unsafe_unretained , weak, assign用于非指针变量。用于
基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等),另外还有id
反正记住:前面不需要加 “*” 的就根据MRC和ARC 以及 iOS sdk来选择使用 unsafe_unretained , weak, assign吧 。

strong\retain:用于指针变量。就是说你定义了一个变量,然后这个变量在程序的运行过程中会被更改,并且影响到其他方法。一般是用于字符串( NSString,NSMutableString),数组(NSMutableArray,NSArray),字典对象,视图对象(UIView ),控制器对象(UIViewController)等
xcode 4.2不支持ARC,所以会频繁使用retain来修饰,用完释放掉,而xcode4.3支持ARC,可以使用retian,不需要手动释放内存,系统会自动为你完成,如果你在xcode4.3上面开发,retian和strong都是一样的,没区别

在内存方面assign是被自动释放的,retain是需要手动去释放。

关于为什么sb拖出的控件默认用的是weak而不是strong ,在知乎上有人给出了答案:
IBOutlet的属性一般可以设为weak是因为它已经被view引用了,除非view被释放,否则IBOutlet的属性也不会被释放,另外IBOutlet属性的生命周期和view应该是一致的,所以IBOutlet属性一般设为weak。如果你那个Outlet 是在第一层 不是在view上的就是 strong的

以上纯属个人理解,有不对的地方请指出,谢谢。

知乎连接:http://www.zhihu.com/question/29927614?sort=created

这里补充几个新的大家看看了解一下:
1.nonnull
@property (nonnull, nonatomic, strong) NSString *name;
nonnull : 标示当前属性不为空,让外界放心用,只做标示用,即使为空,也木有办法
相当于swift里面的 ! 号

2..nullable
@property (nullable, nonatomic, strong) NSString petName;
nullable : 标示当前属性可能为空,让外界使用时注意
相当于swift里面的 ? 号
3.<Person
>
@property (nullable , nonatomic, strong) NSArray *friends;
有点类似于泛型和id的结合,目的是告诉开发人员,数组内装的什么鬼
代表数组内的对象 is kind of 所填的类型 , 当开发人员用的时候不需要再进行从父类强转到子类

那么说了这么多:@property它的存在意义是什么呢? 我个人理解就是自动生成setter getter方法。@property是给编辑器看的。就算你不声明@property,在obj的@implenmention下写好valueA和setValueA,还是可以obj.valueA赋值或取值,但是没有自动联想。还有一个区别是:@property 可以更好的管理内存,我们在括号里写的关键字定义就是。 和public的成员变量有何区别:property可以自己实现存取方法。

以上有的是摘自别人的总结,我感觉很对就拿来了,有什么大家觉得理解不一样的,可以说出来讨论讨论。

我相信此片文章只是浅谈了一下,希望大家能够更深的交流,我也会及时补充一些。

NSObject和id的区别以及Instancetype、id<NSObject>

我们来分析下这三种定义的各自含义和区别 以及最后说到id返回类型都写成Instancetype的好处:

  1. id foo1;
  2. NSObject *foo2;
  3. id <NSObject> foo3;

(1) id类型被称之为 万能指针,也就是可以指向任何对象,可以用于任何类型的对象。

它可以指向的类型不仅限于NSObject

id 我们经常看到运用的地方莫过于

@property (nonatomic, weak, nullable) id delegate;

这个是系统UIKit框架里uitableview定义的 delegate 用的是id的类型.(delegate委托是一种设计模式,是一种设计思想。委托经常依赖协议来实现)

因为我们通常设计一个类的delegate时候,没有办法确定是什么对象来做delegate,所以用id,表示任何对象都可以,这种不能确定类型的需求还是蛮多的,比如有的数组内容类型不一样,进行遍历的时候等。

这里也就体现了动态类型id.可以在代码运行时判断对象的类型。

使用id类型(又称强类型)可以在运行的时候使用任何数据类型来替换。动态类型让程序更加灵活,但会使数据的统一性降低。我们常用的静态类型如NSString等是有着自己的优势的,使用静态类型编译器可以完全分析代码的性能,可预知性更高。

编译器看到id以后,认为是动态类型,不在检查类型

注意的是id 是一个指针,所以在使用id的时候不需要加星号,比如,
id foo=nil;

上述语句定义了一个nil 指针,这个指针指向NSObject 的任意一个子类。

而“id *foo=nil;”则定义了一个指针,这个指针指向另一个指针,被指向的这个指针指向NSObject的一个子类。

id 是Objective-C中的一个特殊的数据类型,还有nil、Nil、SEL…

他们中的大多数都可以在/usr/include/objc/objc.h或者这个目录中的其他头文件中找到。

typedef struct objc_class Class;
typedef struct objc_object {
Class isa;
}
id;

(2) NSObject,NSObject 本身就是定义指向NSObject类型的指针.
NSObject
就是 NSObject类型的指针了,它范围较小。
NSObject对象会惊醒编译时检查(需要强制类型转换)

(3) 然后让我们来总结下id 与 NSObject 区别:
从编译时来看:
1,id关键字在编译时不被检查,而NSObject在编译时会被检查是否被调用一些错误方法。
从范围上来看:
2,id可以是任何对象,包括非NSObject对象
从定义上来看:
3,定义id的时候不使用*,NSObject却需要。
我的理解,基本上来讲,定义id类似于定义了一个地址(只有指针,抽象指针),而NSObject是确实的定义了一个逻辑对象的地址。

(4).id<NSObject>
id<NSObject>告诉编译器,你不关心对象是什么类型,但它必须遵守NSObject协议(protocol),编译器就能保证所有赋值给id<NSObject>类型的对象都遵守NSObject协议(protocol)。这样的指针可以指向任何NSObject对象,因为NSObject对象遵守NSObject协议(protocol),而且,它也可以用来保存NSProxy对象,因为它也遵守NSObject协议(protocol)。这是非常强大,方便且灵活,你不用关心对象是什么类型,而只关心它实现了哪些方法。

(5)instancetype

instancetype是clang 3.5开始,clang提供的一个关键字,表示某个方法返回的未知类型的Objective-C对象。我们都知道未知类型的的对象可以用id关键字表示,那为什么还会再有一个instancetype呢?

instancetype 是一个关键字,它只能用来定义OC方法的返回值类型。

使用 instancetype 编译器和IDE 会做类型检查,而id不会做完整的类型检查。

用instancetype代替id作返回类型有什么好处
1、明确性。代码只做你让它做的事,而不是其他。
2、程式化。你会养成好习惯,这些习惯在某些时候会很有用,而且肯定有用武之地。
3、一致性。让代码可读性更好。
连接
连接
连接

它和id比较:

相同点
都可以作为方法的返回类型
不同点
1 instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;
2 instancetype只能作为返回值,不能像id那样作为参数

总结:instancetype更加智能,编译器知道要返回什么类型,而id则不能,所以以后尽量用 instancetype

以下链接是参考和扩展:
Object-C 类,对象,运行时,isa
连接

动态类型 动态绑定 动态载入 SEL类型:
连接

Objective-C中的id这种数据类型存在的价值是什么?:
连接

iOS数据类型:
连接

Objective-C id 数据类型:
连接

Objective-C中的一些特殊的数据类型 id、nil、Nil、SEL:
连接

Objective-C中的id类型:
连接

如何才能系统的学习 iOS 开发,理解一些规则和深层次的机制原理?
连接

iOS开发中很重要,很常用,但却容易被忽略的知识点:id ,NSObject, id区别
连接

第一次接触OC多态,动态类型与动态绑定 - 小四也软开
连接

C语言基本数据类型简介
连接

Objective-C的内省(Introspection)机制小结
明智地使用内省可以使面向对象的程序更加高效和强壮。
它有助于避免错误地进行消息派发、错误地假设对象相等、以及类似的问题。
连接

Objective-C语法之动态类型(isKindOfClass, isMemberOfClass,id)等
对象在运行时获取其类型的能力称为内省。内省可以有多种方法实现。
连接

在C++中我们知道void*是一个万能指针,或者是叫通用对象,
那么在OC中也有这样一个类似作业的通用对象,叫做id,id是OC中的万能指针,它可以指向任何类型的对象。
如果receiver是id类型,在运行之前编译器是不会给出警告的,因为编译器不知道id中是什么类型,
当程序运行时id中保存对象类型确定,这个时候id的类型也就是消息这个对象的类型。
要是对象所属类中没找到这个类型,运行时程序会有问题
比如说
传递给id的类型是A类型,要是这个类中没有A类型,那么这个程序就会有问题。

Objective-C学习之动态绑定和id类型
连接

id和NSObject *和instanceType的区别与联系 - 顺子为王
连接

iOS中id与NSObject* 和id的区别
连接

id类型的使用与NSObject区别
连接

id 与 NSObject 区别
连接

强类型语言和弱类型语言
连接

instancetype、id、NSObject的区别
连接

instancetype
连接

像这种细节性的问题,一般浮躁的或者不去留心观察的人,不多问几个为什么的人,没有使用次数多的人,是不太会去关注这几个关键字的区别的,这也就是很多程序员之间的差异。思考多的 深入的人,往往能够看得更深入透彻一些,在实际运用中也能更加灵活,更加的有较好的选择性,大多数的问题都可以到网上搜到,但是别人遇到的问题毕竟不是自己的,我们也没有经过那个过程,所以还是勤奋点 多让自己接触点,这样知识涉及的多,思考的也就多了,善于利用搜索引擎和思考实践总结。编程学的其实越来越像一种思维方式了(个人感觉),但是光思考是不行的,最最重要的还是行动去实践检验探究,这样才会变得更加强大,所以大家一起来探讨深入研究吧 哈哈 再絮叨一句 个人感觉这些东西就像金钱一样,掌握的尽可能越多越好,因为以后用到钱用的这些知识的地方会很多,不要等到那个时候再去学再去攒钱或想着一夜致富啥的就太晚了,不要浮躁享受积累的力量吧。

现有三个任务A、B、C。C任务必须要在A B 全部并行执行完毕才能执行

现有三个任务A、B、C。C任务必须要在A B 全部并行执行完毕才能执行。

如果想在dispatch_queue中所有的任务执行完成后在做某种操作,在串行队列中,可以把该操作放到最后一个任务执行完成后继续,但是在并行队列中怎么做呢。这就有dispatch_group 成组操作。比如

dispatch_queue_t dispatchQueue = dispatch_queue_create(“ted.queue.next”, DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t dispatchGroup = dispatch_group_create();
dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
NSLog(@”dispatch-1”);
});
dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
NSLog(@”dspatch-2”);
});
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){
NSLog(@”end”);
});

上面的 log1 和log2输出顺序不定,因为是在并行队列上执行,当并行队列全部执行完成后,最后到main队列上执行一个操作,保证“end”是最后输出。 另外,这里也可以不用创建自己的并行队列,用全局的global,那个也是个并行队列. dispatch_get_gloable_queue(0,0);

http://www.cnblogs.com/zhidao-chen/p/3596981.html

Objective-c如何在C基础上实现面向对象

这里说一下Swift也是基于C和Objective-C,而却没有C的一些兼容约束,关于swift以后的文章还会说,现在先来看看Objective-c如何在C基础上实现面向对象?

面向对象三大特性:封装、继承、多态
在C语言里如果要实现 :
封装:struct实现。

继承:指针实现,就是把父类包含在结构体中。

多态:可以用指针来实现。

具体可参照:
C语言例子
C语言例子

引用总结一句话:面向对象从来都是思想,而不是语言! 理解面向对象的编程思想,我们使用C语言这样的较低级的语言也同样可以实现OOP。像c语言用的里面具体用到的有C语言中的宏,结构体,函数指针, 聚合组合等知识。

接下来我们看看objective-c到底是怎么把c给做到面向对象的:

虽然Objective-C是C的超集,但它不视C的基本类型为第一级的对象。

Objective-C是扩充C的面向对象编程语言。

Objective-C是非常实用的语言。它是一个用C写成、很小的运行库,令应用程序的尺寸增加很小,和大部分OO系统使用极大的VM执行时间会取代了整个系统的运作相反。Objective-C写成的程序通常不会比其原始码大很多。而其函式库(通常没附在软件发行本)亦和Smalltalk系统要使用极大的内存来开启一个窗口的情况相反。因此,Objective-C它完全兼容标准C语言(C++对C语言的兼容仅在于大部分语法上,而在ABI(Application Binary Interface)上,还需要使用extern “C”这种显式声明来与C函数进行兼容),而在此基础上增加了面向对象编程语言的特性以及Smalltalk消息机制。

我自己的理解呢就是把C语言写成了一个面向对象思想的运行库,产生objective-c这样的语言。是不是很有意思?多多思考,饮水思源.C语言还是相当重要的,只不过我们平时开发的一些东西,用不到这些细节而已!但是这些东西还是有必要去明白的,因为个人感觉它们才是不变的东西。如果有一天遇到比较庞大的用户量,对细节要求比较严格的时候,它们就可以灵活运用,来实现底层的一些东西,这样对自己的实现某些功能会更加灵活。想想都觉得有魅力,激动啊! 以上只是个人理解,如果有不对的请批评指出,有不同的意见可以提出来一起讨论检验!

Block

block其实挺强大的,现在来做个总结,从简单到难

简单认识block http://my.oschina.net/u/1418722/blog/233047

利用block代替委托 http://blog.sina.com.cn/s/blog_9e8867eb0102uykn.html

可能会出现的问题:

1.capturing ‘self’ strongly in this block is like
例如:
//如果不写这句话 下面block里就会出现 :capturing ‘self’ strongly in this block is like
__block DNHorizontalSelectController * blockSelf = self;

_navTabbarView.updateTabBarSelectBlock = ^(NSInteger index)
{
    index = index%1000;

    blockSelf.mainScrollView.contentOffset = CGPointMake(self.view.frame.size.width*index, 0);
};

block 是代码块的意思。 甲里引用乙,乙里引用甲,就会导致 “retain cycle” – “形成怪圈”的错误。 网上资料: 解决的办法是 创建一个本地变量 指向 自己(self). 例如:_items 实际上是 self->items, _block 对象在创建的时候会被retain一次 改成: __block ViewController blockSelf = self; _block = ^{ [blockSelf->_items addObject:@”Hello!”]; }; 就可以了。 ——————- DoSomethingManager manager = [[DoSomethingManager alloc] init]; manager.complete = ^{ //…complete actions [manager otherAction]; manager.complete = nil; // Objective-C 用这种方法破坏怪圈。 [manager release]; }; ————…

为什么不用block 是因为通过引用来访问self的实例变量 ,self被retain,block也是一个强引用,引起循环引用,用week是弱引用,当self释放时,weakSelf已经等于nil。
self 持有 block ,block持有 self retaincount==0才会释放 循环了怎么-1

http://blog.csdn.net/youngqj/article/details/49301627

2.block 还是 weak

Blocks可以访问局部变量,但是不能修改

如果修改局部变量,需要加__block

在某個變數前面如果加上修飾字__block 的話(注意block前有兩個下底線),這個變數又稱為block variable。那麼在block裡就可以任意修改此變數值,變數值的改變也可以知道。

block中用到的外部变量最好使用 __weak 修饰,避免内存泄露; block容易引起引用循环的根本原因是:

1,对于(block内部用到的)外部变量,对其执行retain 的时机 与该block的执行时机是不同步的,在block声明的时候就对外部变量进行了retain,而block何时执行甚至是否执行都是不可预测的;

2,block 一般是匿名的,而且copy赋值的,手动释放block对象比较困难

两者的区别:

1.block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
2.
weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
3.block对象可以在block中被重新赋值,weak不可以。
PS:unsafe_unretained修饰符可以被视为iOS SDK 4.3以前版本的weak的替代品,不过不会被自动置空为nil。所以尽可能不要使用这个修饰符。

weak不增加引用,block增加引用
block 是让修改外部变量的值. weak是避免memory cycle

在ARC下不用block 而是用 weak 为了避免出现循环引用

有异议可以提
连接:http://www.bubuko.com/infodetail-782508.html
http://my.oschina.net/u/255456/blog/423991

BSD socket

BSD socket 构成了大多数Internet活动的基础,是网络框架层次体系中的最底层。BSD socket使用C实现,但也可以用在Objective-C代码中。并不推荐使用BSD socket API,因为它并没有在操作系统中插入任何钩子(hook)。比如,BSD socket无法穿过系统范围的VPN,如果Wi-Fi 或是蜂窝无线电被关闭了。调用其API也无法自动激活。Apple建议至少使用CFNetwork或是更高的API.

CFNetwork

CFNetwork API位于基础的 BSD socket之上,用在NSStream. URL 加载系统、Bonjour与GameKit,API的实现中.它为HTTP与FTP等高级协议提供了原生支持.CFNetwork与BSD socket之间的主要差别在于运行循环集成.如果应用使用了CFNetwork。那么输入和输出实践都会在线程的运行循环中进行调度。如果输入与输出事件发生在辅助线程中,就需要以恰当的模式开始运行循环。
CFNetwork比URL加载系统提供了更多的配置选项,这个结果是喜忧参半,在使用CFNetwork创建HTTP请求时可用使用这些配置选项。在创建请求时,需要手工将与请求,一同发送的HTTP头和Cookie信息添加进去。但对于NSURLConnection来说,标准的头与Cookie信息会被自动添加进去。
CFNetwork基本设施构建在Core Foundation层的CFSocket与CFStream API之上。CFNetwork包含了针对特定协议的API,比如用于与FTP服务器通信的CFFTP、用于发送和接收HTTP消息的CFHTTP、用于发布与浏览Bonjour服务的CFNetwork等