zoukankan      html  css  js  c++  java
  • ios笔记

    一.内存管理:

    1.在使用命令行进行编译链接文件的时候,通常是把.m文件单文件编译,然后再把所有的目标文件链接,但是在Xcode中,是把所有的.m文件都进行编译链接的,如果出现重复定义的错误,那大部分问题根源应该就是文件内容被重复包含或者是包含.m文件所引起的。

    2.可以说.h和.m文件时完全独立的,只是为了要求有较好的可读性,才要求两个文件的文件名一致,这也是把接口和实现分离,让调用者不必去关心具体的实现细节。

    3.Xcode是写一行编译一行,有简单的修复功能,红色是错误提示,黄色警告。如果在程序中声明了一个变量,但是这个变量没有被使用也会产生警告信息。在调试程序的时候,如果发现整个页面都没有报错,但是一运行就错误,那么一定是链接报错。

    4.在每个OC对象内部,都专门有4个字节的存储空间来存储引用计数器

    5.栈由编译器管理自动释放的,在方法中(函数体)定义的变量通常是在栈内,因此如果你的变量要跨函数的话就需要将其定义为成员变量。

      栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量等值。

      堆区(heap):一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。注堆和数据结构中的堆栈不一样,其类是与链表。

    6.在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用 @class则不会。

    7.备注:#import 就是把被引用类的头文件走一遍,即把.h文件里的变量和方法包含进来一次,且仅一次,而@class不用,所以后者编译效率更高。

    8.备注:实践证明,A,B相互#import不会出现编译错误。能在实现文件中#import,就不在头文件中#import。

    9.提示:字符串是特殊的对象,但不需要使用release手动释放,这种字符串对象默认就是autorelease的,不用额外的去管内存

    ios中堆栈的区别

    管理方式:

    对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来讲,释放工作有程序员控制,容易产生memory Leak。

    申请大小:

    栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存区域。这句话的意思是栈顶上的地址和栈的最大容量是系统预先规定好的,在Windows下,栈的大小是2M(也有的说1M,总之是编译器确定的一个常数),如果申请的空间超过了栈的剩余空间时候,就overflow。因此,能获得栈的空间较小。

    堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大笑受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

    碎片的问题:

    对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存快从栈中弹出。

    分配方式

    堆都是动态分配的,没有静态分配的堆。栈有两种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配是有alloc函数进行分配的,但是栈的动态分配和堆是不同的,他的动态分配由编译器进行释放,无需我们手工实现。

    分配效率:

    栈是机器系统提供的数据结构,计算机会在底层堆栈提供支持,分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,他的机制是很复杂的。

     

    操作系统ios 中应用程序使用的计算机内存不是统一分配空间,运行代码使用的空间在三个不同的内存区域,分成三个段:“text segment “,“stack segment ”,“heap segment ”。

    “text segment ”是应用程序运行时应用程序代码存在的内存段。每一个指令,每一个单个函数、过程、方法和执行代码都存在这个内存段中直到应用程序退出。

    “heap” 段也称为”data” 段,提供一个保存中介贯穿函数的执行过程,全局和静态变量保存在“heap”中,直到应用退出

    为了访问你创建在heap 中的数据,你最少要求有一个保存在stack 中的指针,因为你的CPU 通过stack 中的指针访问heap 中的数据。

    你可以认为stack 中的一个指针仅仅是一个整型变量,保存了heap 中特定内存地址的数据。实际上,它有一点点复杂,但这是它的基本结构。

    简而言之,操作系统使用stack 段中的指针值访问heap 段中的对象。如果stack 对象的指针没有了,则heap 中的对象就不能访问。这也是内存泄露的原因。

    stack 栈对象的创建

    只要栈的剩余空间大于stack 对象申请创建的空间,操作系统就会为程序提供这段内存空间,否则将报异常提示栈溢出。

    heap 堆对象的创建

    操作系统对于内存heap 段是采用链表进行管理的。操作系统有一个记录空闲内存地址的链表,当收到程序的申请时,会遍历链表,寻找第一个空间大于所申请的heap 节点,然后将该节点从空闲节点链表中删除,并将该节点的空间分配给程序

    例如:

    NSString 的对象就是stack 中的对象,NSMutableString 的对象就是heap 中的对象。前者创建时分配的内存长度固定且不可修改;后者是分配内存长度是可变的,可有多个owner, 适用于计数管理内存管理模式

    两类对象的创建方法也不同,前者直接创建“NSString * str1=@"welcome"; “,而后者需要先分配再初始化“ NSMutableString * mstr1=[[NSMutableString alloc] initWithString:@"welcome"]; ”

     

    二、变量作用域

    1.变量的作用域主要分为四种:

    (1)@public (公开的)在有对象的前提下,任何地方都可以直接访问。

    (2)@protected (受保护的)只能在当前类和子类的对象方法中访问

    (3)@private (私有的)只能在当前类的对象方法中才能直接访问

    (4)@package (框架级别的)作用域介于私有和公开之间,只要处于同一个框架中就可以直接通过变量名访问

    2.变量的作用域补充

    (1)在类的实现即.m文件中也可以声明成员变量,但是因为在其他文件中通常都只是包含头文件而不会包含实现文件,所以在这里声明的成员变量是@private的。在.m中定义的成员变量不能喝它的头文件.h中的成员变量同名,在这期间使用@public等关键字也是徒劳的。

    (2)在@interface  @end之间声明的成员变量如果不做特别的说明,那么其默认是protected的。

    (3)一个类继承了另一个类,那么就拥有了父类的所有成员变量和方法,注意所有的成员变量它都拥有,只是有的它不能直接访问。

     

    2017.05.05

    在OC中,所有跟角度相关的数值,都是弧度值,180° = M_PI

    正数表示顺时针旋转

    负数表示逆时针旋转

    提示:由于transform属性可以基于控件的上一次的状态进行叠加形变,例如,先旋转再平移。因此在实际动画开发中,当涉及位置、尺寸形变效果时,大多修改控件的transform属性,而不是frame、bounds、center 。


    15 // instancetype会让编译器检查实例化对象的准确类型
    16 // instancetype只能用于返回类型,不能当做参数使用

    3.instancetype & id的比较

    (1) instancetype在类型表示上,跟id一样,可以表示任何对象类型

    (2) instancetype只能用在返回值类型上,不能像id一样用在参数类型上

    (3) instancetype比id多一个好处:编译器会检测instancetype的真实类型

    1)使用KVC间接修改对象属性时,系统会自动判断对象属性的类型,并完成转换。如该程序中的“23”.

    2)KVC按照键值路径取值时,如果对象不包含指定的键值,会自动进入对象内部,查找对象属性

    在上面代码中imageView.userInteractionEnabled = YES;的作用是,设置imageView为允许用户交互的。imageView默认的是不允许用户交互的

    蓝色文件夹(folder)一般作为资源文件夹使用,与黄色文件夹的主要区别是不参与编译,所以说如果你在这些文件夹下编写的逻辑代码是不参与编译的,其他文件也不能直接引用它们,若引用其中文件需要全路径。

    黄色文件夹(group)是逻辑文件夹,主要是为了逻辑上的分组,如果手动创建(通过New Group选项)group并不会真正创建一个文件夹文件,该文件夹下的文件则会散乱的存放在工程根目录下。当然我们通常会让Xcode中的文件树与实际工程文件中的文件树保持一致。

    既然两种都可以对状态栏进行管理,那么什么时候该用什么呢?
    如果状态栏的样式只设置一次,那就用UIApplication来进行管理;
    如果状态栏是否隐藏,样式不一样那就用控制器进行管理。
    UIApplication来进行管理有额外的好处,可以提供动画效果。
     
    程序启动原理

    UIApplicationMain

    main函数中执行了一个UIApplicationMain这个函数

    intUIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);

    argc、argv:直接传递给UIApplicationMain进行相关处理即可 

    principalClassName:指定应用程序类名(app的象征),该类必须是UIApplication(或子类)。如果为nil,则用UIApplication类作为默认值

     delegateClassName:指定应用程序的代理类,该类必须遵守UIApplicationDelegate协议

    UIApplicationMain函数会根据principalClassName创建UIApplication对象,根据delegateClassName创建一个delegate对象,并将该delegate对象赋值给UIApplication对象中的delegate属性

    接着会建立应用程序的Main Runloop(事件循环),进行事件的处理(首先会在程序完毕后调用delegate对象的application:didFinishLaunchingWithOptions:方法)

    程序正常退出时UIApplicationMain函数才返回

    系统入口的代码和参数说明:

    argc:系统或者用户传入的参数
    argv:系统或用户传入的实际参数 
    1.根据传入的第三个参数,创建UIApplication对象
    2.根据传入的第四个产生创建UIApplication对象的代理
    3.设置刚刚创建出来的代理对象为UIApplication的代理
    4.开启一个事件循环(可以理解为里面是一个死循环)这个时间循环是一个队列(先进先出)先添加进去的先处理
    
    

    四、程序启动的完整过程

    1.main函数

    2.UIApplicationMain

    * 创建UIApplication对象

    * 创建UIApplication的delegate对象

    3.delegate对象开始处理(监听)系统事件(没有storyboard)

    * 程序启动完毕的时候, 就会调用代理的application:didFinishLaunchingWithOptions:方法

    * 在application:didFinishLaunchingWithOptions:中创建UIWindow

    * 创建和设置UIWindow的rootViewController

    * 显示窗口

    3.根据Info.plist获得最主要storyboard的文件名,加载最主要的storyboard(有storyboard)

    * 创建UIWindow

    * 创建和设置UIWindow的rootViewController

    * 显示窗口

    代理的内存警告:当application发生一些事情的时候(接收到内存警告的时候),会先通知它的代理,之后代理会通知它的window,window会通知它的根控制器,根控制器会通知它的子控制器。内存警告是由上往下一层一层往下传的。
     
    应用程序启动之后,先创建Application,再创建它的代理,之后创建UIwindow。UIWindow继承自UIview。
     
  • 相关阅读:
    titanium开发教程0206创建多行的选择器
    titanium开发教程0210创建的文本字段与嵌入的按钮
    titanium开发教程0209配置文本域和文本区键盘类型
    titanium开发教程0301理解tab group
    titanium开发教程0205创建单行的选择器
    linux shell删除文本每行末尾的单个或者多个空格或者制表符
    R语言中scale函数的用法
    R语言中批量提取当前目录中指定类型的文件
    python中提取包含指定字符的行、提取以指定字符开头、指定字符结尾的行
    python中如何统计文件的行数
  • 原文地址:https://www.cnblogs.com/zhengyumin/p/6773311.html
Copyright © 2011-2022 走看看