精华内容
下载资源
问答
  • C入门:文件复制

    2011-08-03 09:10:24
    C入门 文件复制
    long copyFile(const char* src, const char* dest)
    {
        long count = 0L;
        FILE* fileIn;
        FILE* fileOut;
        int readLen;
        int buffer_len = 512;
        unsigned char buffer[buffer_len];
        size_t size = sizeof(unsigned char);
    
        if(!(fileIn = fopen(src, "rb")) )
        {
            printf("open %s file fail.\n", src);
            return -1;
        }
    
        if(!(fileOut = fopen(dest, "wb+")) )
        {
            printf("create/open %s file fail.\n", dest);
            return -1;
        }
    
        while(0 < (readLen = fread(buffer, size, buffer_len, fileIn) ) )
        {
            count+=readLen;
            fwrite(buffer, size, readLen, fileOut);
        }
    
        fclose(fileIn);
        fclose(fileOut);
    
        return count;
    }

    #include <stdio.h>
    #include <stdlib.h>
    展开全文
  • Objective-C入门

    万次阅读 2007-12-14 10:18:00
    Objective-C入门 A first look at ObjC(中文版) 转自: http://www.fish888.com/Objective-C-t68418Objective-C入门(A First Lo

    Objective-C入门


    A first look at ObjC(中文版)
    转自: http://www.fish888.com/Objective-C-t68418

    Objective-C入门(A First Look at Objective-C)

    原著:Noah Roberts (jik)
    翻译:jeff_yecn

    顾名思义,Objective-C就是面向对象的C语言。你可以使用Objective-C编程,但不使用任何非C语言的东西。但那样将是对这语言的浪费。Objective-C使用所有的C语言的内容,同时添加了一些使得它更具面向对象特征的语法。本指南假定你已经知道什么是面向对象编程,同时熟悉C(你不必是这方面的专家,但是我不打算在这里教你应该已经知道的东西)。
    我同时必须建议你不要仅仅读这一篇文章,因为它远远不是在Objective-C(ObjC)方面的终极资源。在互联网上你可以找到其它更好、更详细的学习这种语言的资料。在我的网站:members.xoom.com/jik_you上有一些链接,也许你可以从那里开始搜索。
    ObjC,和其他面向对象语言一样,是围绕着对象的,所以让我展示一下对象的构成。在ObjC中,对象有两部分。它有一个界面,是对象的外在表现。同时它有一个实现,就是它的内部工作机制。换句话说,就是外界看到的部分和看不到的部分。有时,这样更容易理解。

    界面

    在ObjC中,界面通常有它自己的头文件(通常是.h),但并不是一定要这样。你可以把界面和实现放在一个文件中,或者把几个界面放在一起,但每个界面是不同的,你必须对此很清楚,否则将会感到非常苦恼。我将只使用在头文件中定义界面的办法。
    首先,你必须导入这个对象的超类的界面。你可以使用与“#include”相同语法的预处理标识“#import”。事实上,两者之间的区别只是#import会进行检查以确保文件仅被包含一次。有些人选择使用#include,这完全符合语法,但ObjC设计是使用#import,你也许愿意考虑这一点而保护你的界面文件。
    如果你使用gcc(或egcs等)来作为你的编译器,也许你会愿意使用开关:-Wno-import,否则,gcc会无休止地提示你使用import来代替include。
    因此,以下是以一个对象为超类的新类的第一行代码,也通常是所有类的开头。
    #import /* gcc运行时库的对象 */
    现在,如果你计划引用其他的类,你可以导入他们的头文件,更好的办法是使用@class来声明这些标识是类。界面并不需要知道这个类是什么和怎么做的全部信息,所以引用它的头文件并没有作用,让我们使用@class。
    @class String; //简单吧?
    顺便说一下,ObjC同时使用“//”和“/* */”来作为注释,这有时会比较方便。
    好了,现在我们准备让世界知道想要什么类型的对象,所以让我们声明它。首先我要说明的是我在声明一个新类,在此之前,你应该定义好这个新类的超类。
    @interface NewClass : Object //新类在左边,超类在右边。
    我并没有漏掉“;”,就是这样写的。
    现在我们声明实例变量,不管他们是不是私有的(我碰巧认为私有的东西是不应该被人看见的,实际上也是这样:P)。我在一对“{}”中间写上,就象我们在C的结构中做的那样。
    {
    @public
    int aValue;
    @protected //缺省情况下只能被子类所见
    int value2;
    @private //不可见
    int mrInvisible;
    }
    做完这些以后,我们要放入method的原型定义。method只能是公共的,虽然如果我愿意的话,我可以演示给你看如果你访问一个私有的method的时候会产生的编译器警告信息。
    method既有“类”的(也有些人叫做“工厂”的),也有“实例”的。类method只能由类对象访问,实例method显然由实例访问。例如,我声明了一个保存实例的变量,但在我使用它之前,我必须使用一个类method来产生一个这个变量指向的实例,这样我才可以调用它的实例method。我这样做了以后,我就不能再访问它的类method了。在我释放对象实例之前,我只能访问它的类method。描述一个method时,你根据它是类method还是实例method响应在前面放上“+”或“-”的符号。然后,在“( )”中你填入method返回值的类型,除非你返回的是代表任何对象的通用类型id。在然后,如果你的method有参数的话,你先写一个“:”,跟着是在“( )”中间的参数类型,再接着是变量名。你可以一直写下去,直到以“;”结束。
    同时,在第一个参数之后和下一个“:”之前,你还可以放入一些单词,但单词与“:”之间不能有空格。
    也许你现在已经糊涂了,让我们看一个类和实例method。
    +createWith: (int)value; //足够简单
    -(void)say: (String *)what to: (String *)name; //第一个参数是what,
    // to是method名称的一部分。
    在参数表中间使用额外的单词可以使得method念起来更容易理解。就象上面第二个method,念起来象“say 'Hello' to jik”,而不是“say 'Hello', jik”。
    可变长度参数表的语法和C语言中是一样的:
    -(void)doStuff: (id)format,...;
    最后,当我们完成全部的定义以后,我们通过下面的语句告诉编译器我们完成了:
    @end
    这里谈的都是关于对象的。你可以使用typedef或其他在C中可以放入头文件的语法继续定义对象。

    名字的小规则

    method名由除了+/-,类型和参数以外的所有东西组成。例如,method“-(void)say: (String *)what to: (String *)name”的名字在内部是“say:to:”。如果你使用gdb ObjC补丁,这也是用名字引用method的方法。
    同时,你应该记住ObjC通常会被处理为C语言并传递到C编译器。过程中名字通常会发生改变,你应该牢记这一点而不要做可能会迷惑编译器的事......就好象:
    -roll_d: (int)sides;
    -roll: (int)count d: (int)sides;
    在这个例子中,两个method都会被gcc编译器转化为以下的C函数:
    __i_ClassName_roll_d_()
    这个事情发生过在我身上,所以相信我,千万小心。如果我是你的话,我不会在method名的中间使用“_”,在开头使用则没有什么问题。

    消息

    由于你在实现中将经常使用消息,我们必须首先讨论他们是什么以及在语法上怎么表达。一个消息只是对象method的简单调用。在面向对象编程中,由于它就好象给一个对象发送消息告诉它做某些事,因此称作消息。要表达一个消息,首先是对象的名字,跟着是你要它执行的method以及你要传递的参数,这一切用“[ ]”包围起来。
    例如:
    [object jumpAround];

    [object jump: forward];
    “object”可以是一个类也可以是类的一个实例。通常类以大写字母开头,而实例则以小写开头。如果“object”是类的话,你只能要求它执行类method,反之亦然。
    例如,要建立类“Object”的一个新实例,我们可以使用...:
    [Object alloc];
    “alloc”是为新对象分配内存的类method。但这样并不能使得对象能够使用,因为它的实例变量还没有初始化...要那样做的话,我们调用“init”...因此,我们需要做的全部事情是:
    id object=[Object alloc];
    [object init];
    如果消息的返回值的类型合适的话,你也可以使用它作为另一个消息的一部分。由于“alloc”消息返回id类型,我们可以用这个返回值作为消息发送的对象。由于空返回值不能做任何事情,因此通常返回id会比返回void要好。在你的method执行完成后,最好能够返回指向当前对象自身的变量“self”,除非你不想它作为其他消息的参数或发送对象...如果那样的话,返回void吧。一个使用空返回值的好例子是释放内存的method,不好的例子是分配内存的时候。所以,我们可以使用这个特性来在一行中完成分配内存和初始化的工作:
    id object=[[Object alloc] init];
    当然,你必须确定init method也返回id,否则我们不能继续使用“object”变量。
    消息的执行按照先进先出的顺序。如果你把一个消息作为另一个消息的一部分,所有的内层的消息回在外层的消息执行前执行和返回。最终的返回值为最后一个执行的消息的返回值,内层的消息不会在最后返回。



    实现

    这是对象完成所有工作的部分。它定义所有对象的method的内部工作机制,准确的说,是所有非继承的部分。实现文件的后缀为“.m”。
    首先,你需要导入类自己的和这个对象中将要用到的类的头文件。象通常一样,你可以做额外的define,typedef以及其他你可能会在C源程序开头做的事情。
    当你完成所有的准备工作,你告诉编译器你开始定义一个新对象的实现部分。你用与界面定义类似的method来进行,但你不在需要指明超类是什么,除非你没有为这个对象创建一个界面(这是可能做到的)。
    当然,如果你愿意的话,你也可以在说明一次超类是什么,没有任何规定说明你不能那样做。你可以用创建界面定义一样的method来做。
    @implementation NewClass
    在这里你不需要添加实例变量,所以在实现中不需要包括那一部分。我们现在要做的是定义新的method,以及我们需要覆盖的继承下来的method。有关的语法是一种界面中的method声明和C函数的交叉。
    以下是一个简短的method定义的例子:
    -sayHello
    {
    ? printf("Hello world! ");
    ? ? ? return self;
    }
    下面一个例子是有参数使用消息的:
    -say: (String *)What
    {
    ? ? printf("%s ",[what cString]);
    ? ? ? return self;
    }
    你用与界面定义相同的method结束实现定义。
    @end

    特殊的method

    当你在派生一个类的时候,你要知道有些method的情况有些特殊。在不同的API中,它们的称呼有所不同,但其中相似的已经分类在一起。有些method在多数情况下都不应该被覆盖,有些可以被覆盖,在你这样这样做的时候必须满足一些特定的要求。
    你不应该覆盖“alloc”method。这个method做了些特别的事情来为新的实例分配存储空间。它已经被在Object中定义成能够为你需要创建实例的任意类分配正确的存储空间。如果你覆盖它,你的类很可能不能正确工作。
    如果你使用函数库使用一种引用计数技术,例如libFoundation使用自动释放池来进行对象清除,你不能覆盖release,autorelease和retain method。这些method使用特别的东西来跟踪对象的引用。改变其中任何一个method会打乱整个体制。
    init method可以被覆盖,但你必须保证在做其他事情之前调用超类的init method,否则有些变量可能会没有初始化。总是在覆盖的init method的第一行写上[super init];。对你的库函数中使用的dealloc或free method,同样需要调用超类的method,但是是在结尾。而不是method的开头。简单地把“return [super dealloc];”放在最后一行就足以确保完成超类所需要的所有清除工作。

    非标准的问题

    ObjC有许多的分支。对各种语言的功能和运行时支持没有一个绝对的标准。各种ObjC编译器之间并不兼容。这很大程度上意味着你要定位于一种编译器,因为它们之间的差异是如此的大,以至于你不能使用#ifdef来编写跨编译器代码。
    不但运行时库是完全不同,语言也有不同的扩展。比如,ObjC的有些类型如“类别(Catagory)”和“协议(Protocol)”并没有在全部编译器上实现。有些有,有些没有。我肯定这可以更深入的讨论,而这仅仅是问题的表面。
    在选择编译器的时候,你必须要理解这一点。有些编译器,象POC,能够跨平台兼容,但缺少语言中的一些部分。有些更完整些,但仍然缺少一些重要的部分,比如,gcc是ObjC的一个比较完整的实现,但仍然缺少对模块卸载的支持(ObjC建议具有在运行时添加和移除一些部分的能力,gcc可以加载他们,但不能移除)。
    有些编译器之间存在一些关系。象Stepstone和POC更多地来自于由Brad Cox编写的该语言的最初实现版本。其它的,象gcc,更多地来源于NeXT。
    他们之前都是不同的,如果不重写一大部分源代码,并不能在另一个环境下进行编译(假如存在这种可能的话)。记住这一点,下面我将介绍一些不那么具有可移植性的概念。在此之前,我讲的内容包括在ObjC的所有实现中。现在我们要进入不是那么标准的领域。

    新数据类型

    ObjC有一些我现在应该提一下的新数据类型。其中的有些类型的名称可能会有不同,或者有些没有实现。你要验证一下你的编译器是否支持。
    BOOL是布尔类型,可以是YES或NO,NO为0,YES为非0。
    STR为char *。
    IOD为FILE *。
    id是代表任何ObjC对象的通用类型。
    SEL类型是代表method的变量。你可以要求对象执行SEL代表的method。你用@selector(methodName)来创建SEL。“methodName”是method名的ObjC表示形式。例如前面提到的“say:to:”。
    IMP用C语言指针代表一个method。这用于你需要节省寻找消息的处理程序的时间的情况下,因为IMP是对method的直接链接。通常用于需要高速度的循环过程中。
    这些也许对你来说基本够用了......象我前面说过的,这篇文章不应该是关于ObjC的唯一资源。

    类别(Catagory)

    类别是扩展对象能力的一种方法。你可以在对象中添加新的method,但你不能添加新的实例变量。新的method被视为扩展的类的一部分,子类将继承这些新的δ堋D阋部梢酝ü?唇ㄏ嘤Φ睦啾鹄锤哺抢嗟method。如果你有两个覆盖一个类的method的类别,究竟哪一个覆盖并不确定。
    类别的语法与类的语法相似。他们都有界面和实现。当然,也有一些轻微的差别。类别定义的开头几行象这样:
    @interface ClassName (CatagoryName)
    @implementation ClassName (CatagoryName)
    ClassName是你要扩展的类的名称,CatagoryName是类别的识别的名称。类别可以访问所扩展的类的实例变量。
    其余的语法是相同的:在界面中声明method,在实现中定义它们,并以@end结束。
    你可以用类别建立私有method。把类别的界面放在类的实现文件的实现代码的前面。然后把你需要作为私有mthod的放在这个类别中。创建对象的实现,然后,在这个文件的末尾,加入类别的实现。这样可以对外隐藏这些method,如果在其他地方试图访问这些method,编译器将会给出警告。它不能够在运行时避免被访问,而只能在编译时警告你。在ObjC中没有办法禁止method被访问。

    协议(Protocol)

    协议,顾名思义,定义一组类之间相互遵守的行为规范。协议没有界面和实现,但他们与界面更加相似。你不需要添加新的实例变量,也不添加新的method或定义任何method的内部实现。协议所需要做的只是定义一套要求所有类都必须包含的method,以遵循这个协议。
    协议在你使用ObjC的动态类型机制的时候特别有用。ObjC拥有和Java类似的运行时的动态类型。这是它优于C++的一点,C++只支持“编译时”的动态类型。
    比如你要创建一个可以接受任何对象的method。你必须确定这个对象可以响应你要发送的消息,否则你将会发送这个对象不明白的消息给它。这会导致一些问题。如果你使用了协议,你就可以确保它能响应你将要发给它的许多消息,如果你仅是需要发送一个消息,你还有其它方法来检查......这一点我留给你自己去研究。
    同时,在上述的情况中,你还可以使协议要求你所期望的参数。我现在会展示给你看怎么完成这些工作。
    定义一个新的协议,首先:
    @protocol ProtocolName
    接着是任意数量的method的声明,请使用在界面定义的相同的语法。最后以@end结束。
    现在,为了遵循这个协议,你首先声明你要创建的新对象的界面的内容。然后,你必须在这个对象的实现中定义协议中的所有method。
    @interface NewObject : Object
    上述的语句告诉编译器这是一个叫NewObject的对象,它的超类是Object,并要符合ProtocolName的协议。
    要查询一个对象是否满足特定的协议,可以使用“conformsTo"的mthod。
    [object conformsTo:@protocol(ProtocolName)];
    这会根据对象是否符合的情况返回YES或NO。
    要查询一个参数是否符合特定的协议,可以象如下地声明method:
    -method:(id)argument;
    (译注:原文如此,在gcc中似乎并不支持,按照逻辑来说应该为:-method:(id ) argument;)
    你也可以返回满足协议的对象:
    -(id ) method;

    结论

    好了,以上就是关于ObjC的快速和琐碎的介绍,要学习它,你需要继续阅读其他的信息资源。我的网站有一些链接,除此以外......做一个网站搜索或询问一下。我会给你一个简短的例子,它可以用gcc编译。

    Noah Roberts (jik)
    原作者授权声明:
    我在此授权,可以免费将本文以任何形式或格式进行复制和分发,但这个版权声明必须出现在正文内或复制品内(在复制品内,它必须明显地可以被读者读到)。你可以编辑本文以修复拼写和语法错误。但你不能以任何形式修改它的内容。如果你不同意这个授权协议,你应该联系我来复制本文档。
    “I herby grant, free of charge, the right to copy and redistribute this
    work whole in any form or format, as long as this copyright notice
    appears intact somewere on or about the copy (it must be obviously
    available to the reader of the copy, from the copy). You may edit this
    document to fix spelling or gramatical errors, but you must not modify
    it's content in any other way. If you object to this licence you must
    contact me for permission to copy this document.”

    最后修订:1999年3月16日
     
    展开全文
  • Objective-C 入门

    千次阅读 2019-07-07 00:53:50
    本文侧重介绍常用的语法,通过对比Java并结合本人入门的过程和经验,帮助有需求的同学快速掌握OC基本编程,为IOS的入门奠定语言基础。首先是写第一行代码,恭喜正式进入OC学习阶段。 int main(int argc, char *argv...

    前言

    Objective-C is the primary programming language you use when writing software for OS X and iOS. It’s a superset of the C programming language and provides object-oriented capabilities and a dynamic runtime. Objective-C inherits the syntax, primitive types, and flow control statements of C and adds syntax for defining classes and methods. It also adds language-level support for object graph management and object literals while providing dynamic typing and binding, deferring many responsibilities until runtime.

    Objective-C(下面简称OC)是由C语言和Smalltalk扩展出来的,是C语言的超集,最大的区别是OC是面向对象的,其火星文写法对于之前从事Java开发的同学颇感蛋疼,OC最大特点之一是使用“消息结构”而不是“函数调用”,所以在运行时执行的代码由运行环境决定,而Java是由编译器决定。个人感觉有关于IOS学习的文章相较于Android质量较低,有可能是苹果系统封闭的原因,本文侧重介绍常用的语法,通过对比Java并结合本人入门的过程和经验,帮助有需求的同学快速掌握OC基本编程,为IOS的入门奠定语言基础。下面首先是写出第一行代码,恭喜正式进入OC学习阶段。

    int main(int argc, char *argv[])
    {
        @autoreleasepool //创建自动内存释放池
        {
        	//打印输出
            NSLog(@"hello world ios!");
            return 0;
        }
    }
    

    下面介绍OC代码的文件扩展名:

    文件扩展名 类型
    .h 头文件,作用是对类、属性、变量、函数等的声明
    .m 实现文件,对头文件的生命实现或者扩展
    .mm 实现文件,一般是C++代码

    如果实现文件需要引入头文件时,推荐使用#import,跟#include作用相同,优化了确保相同文件只会被引入一次,所以倾向用#import。

    基本数据类型

    包括:int float double char
    
    类型 字节数 格式化输出
    char 1 %c
    int 4 %i,%x,%o
    unsigned int 4 %i,%x,%o
    short int 2 %hi,%hx,%ho
    unsigned short int 2 %hi,%hx,%ho
    long int 8 %li,%lx,%lo
    unsigned long int 8 %lu,%lx,%lo
    long long int 8 %lli,%llx,%llo
    unsigned long long int 8 %llu,%llx,%llo
    float 4 %f
    double 8 %f
    long double 16 %Lf

    其他数据类型

    id类型

    可以存放任何数据类型的对象,类似Java中的Object类,其被定义为指向对象的指针(本身就是指针了),故定义比如id instance = nil;id类型是多态和动态绑定的基础。

    BOOL类型

    布尔值为YES/NO或1/0。Java对应是true/false

    nil和Nil

    nil相当于Java中的null,表示一个对象,这个对象的指针指向空。Nil是定义一个指向空的类而不是对象。

    NSString(不可变字符串)

    字符串是非常重要常用的,务必要掌握常用的基础用法,包括创建、截取、遍历、比较、大小写转换、搜索等,语义跟基本类似Java。

    		//字符串
            NSString *str1 = @"ABC3456789";
            //拼接成新的字符串
            NSString *str2 = [str1 stringByAppendingString:@"wwww"];
            NSLog(@"str = %@", str2);
            //遍历
            for (int i = 0; i < [str2 length]; i++) {
                char temp = [str2 characterAtIndex:i];
                NSLog(@"字符串第 %d 位输出 %c", i, temp);
            }
            //比较
            // sEqualToString方法 :比较字符串是否完全相等,大小写不一样也无法完全匹配。
            //hasPrefixe方法:逐一匹配字符串头部。haSuffix方法:匹配字符串的尾部
            if ([str2 isEqualToString:str1]) {
                NSLog(@"相等");
            }
            if ([str2 hasPrefix:@"www"]) {
                NSLog(@"有该头部");
            }
            if ([str2 hasSuffix:@"www"]) {
                NSLog(@"有该尾部");
            }
            if ([str2 compare:str options:NSCaseInsensitiveSearch | NSNumericSearch] == NSOrderedSame) {
            }
            NSLog(@"比较结果:%d", [str2 caseInsensitiveCompare:str1]);
            //大小写转换
            NSLog(@"str3转大写:%@",[str2 uppercaseString]);
            NSLog(@"str3转小写:%@",[str2 lowercaseString]);
            NSLog(@"str3首字母转大写:%@",[str2 capitalizedString]);
            //字符串截取
            NSRange rang = NSMakeRange(2, 2);
            NSLog(@"str3截取:%@",[str2 substringWithRange:rang]);
            //搜索
            NSRange rang1 = [str2 rangeOfString:@"www"];
            NSLog(@"location: %d,length: %d",rang1.location,rang1.length);
            //替换
            //全部替换
            NSString *str3 = [str2 stringByReplacingOccurrencesOfString:@" " withString:@"@"];
            NSLog(@"替换后字符串为%@", str3);
            //局部替换
            NSString *str4 = [str2 stringByReplacingCharactersInRange:rang withString:@"met"];
            NSLog(@"替换后字符串为%@", str4);
    

    NSMutableString(可变字符串)

    创建对象的基本写法是[[NSMutableString alloc]init],*号代表对象,[]代表方法调用,只能通过类或者对象才能调用。[NSMutableString alloc]类似Java中new得到一个对象,然后再调用init初始化方法。

    		//创建对象并初始化
    		NSMutableString *mStr = [[NSMutableString alloc]init];
            //appendstring:向字符串尾部添加一个字符串。
            //appendFormat:向字符串尾部添加多个类型的字符串,可以添加任意数量与类型的字符串。
            [mStr appendString:@"hello world!"];
            NSLog(@"字符串创建%@", mStr);
            [mStr deleteCharactersInRange:[mStr rangeOfString:@"hello"]];
            //删除
            NSLog(@"字符串删除%@", mStr);
            //插入
            [mStr insertString:@"love you" atIndex: mStr.length];
            NSLog(@"字符串插入%@", mStr);
    

    NSInteger、NSUInteger和NSNumber

    NSInteger不是一个对象,而是基本数据类型中的typedef,NSUInteger是无符号的。 当需要使用int类型的变量时,推荐使用NSInteger,这样不需要考虑设备是32位或者64位。NSNumber是一个类,用于包装基本数据类型成为对象,可以理解为Java中的装箱,为一些集合只能存放对象使用,通过字面量方式非常方便将基本数据类型转成对应的对象。例如:

    		//包装
    		NSNumber *intNumber = [[NSNumber alloc]initWithInt:43];
            //或者字面量方式
            NSNumber *intNumber1 = @43;
            //还原基本数据类型,解包
            NSLog(@"%d",[intNumber intValue]);
    

    集合

    集合不能接受nil,nil是作为集合结束标识符
    1. NSArray(不可变)
    类似Java中的ArrayList,可以存储不同类型的对象,一般情况下数组元素的类型是相同的,特点是有序、可重复。下面展示一位数组的基本操作:

    //字面量创建方式
        NSArray *arr2 = @[@"aaa",@"bbbbb"];
    //工厂方法创建
        NSArray *array = [[NSArray alloc] initWithObjects:@"1", @"2", nil];
        //取最后一个元素
        [array lastObject];
    //    取第一个元素
        [array firstObject];
    //    数组是否包含某个元素
        [array containsObject:@"1"];
    //    数组的大小
        int count = (int) array.count;
    //    第一种方式遍历
        for (int i = 0; i < count; i++) {
            NSString *_str = [array objectAtIndex:i];
        }
    

    那么数据要求是多维的呢?多维数组可以理解为数组的数组,通过嵌套的方式,创建如下:

    	    // 字面量创建二维数组并访问
            NSArray *arr2 = @[@[@11, @12, @13], @[@21, @22, @23], @[@31, @32, @33]];
            // 字面量访问方式(推荐)
            NSLog(@"arr2[2][2]:%@", arr2[2][2]);
            // 数组对象函数访问
            NSLog(@"arr2[2][2]:%@", [[arr2 objectAtIndex:2] objectAtIndex:2]);
    

    2. NSMutableArray(可变的)
    派生于NSArray,理解为动态数组,提供增加、删除、插入、替换等语法糖。

    		//创建,当然还有其他方式
            NSMutableArray *mutableArr = [NSMutableArray arrayWithObjects:@"one",@"two",@"three", nil];
            //添加
            [mutableArr addObject:@"hello"];
            //替换
            [mutableArr replaceObjectAtIndex:2 withObject:@"tihuan"];
            //删除
            [mutableArr removeObjectAtIndex:1];
            //插入
            [mutableArr insertObject:@"ios" atIndex:1];
    

    多维数组创建方式如下:

       		// 初始化作为列的数组,看做4列
            NSMutableArray *columnArray = [[NSMutableArray alloc]initWithCapacity:4];
    
            // 初始化2个一维数组,每个一维数组有4个元素,看做1行4列,2行加起来就是2行4列
            NSMutableArray *rowArray1 = [[NSMutableArray alloc]initWithCapacity:4];
            NSMutableArray *rowArray2 = [[NSMutableArray alloc]initWithCapacity:4];
    
            // 每个行依次增加数组元素
            // 第一行
            [rowArray1 addObject:@"11"];
            [rowArray1 addObject:@"12"];
            [rowArray1 addObject:@"13"];
            [rowArray1 addObject:@"14"];
    
            // 第二行
            [rowArray2 addObject:@"21"];
            [rowArray2 addObject:@"22"];
            [rowArray2 addObject:@"23"];
            [rowArray2 addObject:@"24"];
    
            // 分别打印数组
            NSLog(@"myRowArray1: %@", rowArray1);
            NSLog(@"myRowArray2: %@", rowArray2);
            NSLog(@"myColumnArray: %@", columnArray);
    

    字典

    类似于Java中的HashMap,是一种映射型数据结果,存储键值对,有可变和不可变两种类型。
    NSDictionary
    主要特点是不可变,如果集合初始化完成,将内容无法修改,无序。

    	//标准创建
        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"cat",@"name1",@"dog",@"name2", nil];
        //字面量创建
        NSDictionary *dict1 = @{@"name1":@"cat",@"name2":@"dog"};
    	//第一种遍历
        for (NSString *key in [dict1 allKeys]) {
            NSLog(@"key: %@,value: %@", key, dict1[key]);
        }
        //第二种遍历方式,通过遍历器
        NSEnumerator *rator = [dict keyEnumerator];
        NSString *temp;
        while (temp = [rator nextObject]) {
            NSLog(@"%@", temp);
        }
        //获取元素
    	dict1[@"name"];
    	[dict1 objectForKey:@"name"];
    	//集合元素的个数
    	NSInteger count = dict1.count;
    	//沙盒文件存储和读取Plist
    	[dict5 writeToFile:@"路径" atomically:YES];
    	NSDictionary *dict7 = [NSDictionary dictionaryWithContentsOfFile:@"路径"];
    

    NSMutableDictionary
    NSMutableDictionary是NSDictionary的子类。NSMutableDictionary是可变的,动态添加、更改、删除元素,因此不能使用字面量方式(@{})来创建一个可变字典。如果是不可变字典,出现了同名的key,那么后面的key对应的值不会被保存,反之是可变字典,出现了同名的key,那么后面的值会覆盖前面的值。

    //创建
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    //添加
    [dict setObject:@"dog" forKey:@"name"];
    [dict setValue:@"18" forKey:@"age"];
    //会将传入字典中所有的键值对取出来添加到dict中
    [dict setValuesForKeysWithDictionary:@{@"name1":@"dog"}];
    //取元素
    [dict objectForKey:@"name"];
    dict[@"name"];
    //删除
    [dict removeAllObjects];
    [dict removeObjectForKey:@"name"];
    [dict removeObjectsForKeys:@[@"name", @"age"]];
    //更新,如果利用setObject方法给已经存在的key赋值,新值会覆盖旧值
    [dict setObject:@"20" forKey:@"age"];
    dict[@"age"] = @"30";
    

    NSSet && NSMutableSet

    具有很好的存取和查找功能,与NSArray相比NSSet的元素没有索引,特点是无序,不可重复,类似Java中的HashSet,其中NSMutableSet提供计算交并集的方法。
    NSSet存储元素的过程:

    NSSet添加一个对象
    调用对象的Hash方法得到hashCode
    对象在底层Hash表的位置
    位置冲突类似Java的HashSet

    注意:推荐使用字面量方式创建对象,可以缩短代码长度,增加可读性。但是在创建数组的时候要注意,如果含有nil就会抛异常,因为字面量实际上”语法糖“,效果等同于先创建一个数组,然后再把所有的对象添加进来,保证数组不添加nil。

    消息传递

    前言提到Objective-C最大特点之一是继承了Smalltalk消息传递模型,因此在OC中的方法调用准备的说法是消息传递,类别与消息关系松散,调用方法是给对象发送消息,而方法是对消息的回应,所有消息的处理直到运行时(即runtime)才会动态确定,并交由类自行决定如何处理收到的消息。总结是一个类不保证一定会回应收到的消息,当收到的一个无法处理的消息,会抛出异常。
    Java或者C++方法调用:

    obj.method(argument);
    

    OC方法调用:

    [obj method: argument];
    

    我们都知道在Java或者C++中,如果类没有定义method方法,那么编译肯定不会通过,但是在OC中,理解是发送method的消息给obj,obj收到消息后再决定如何回应消息,如果类内定义了method方法则运行,反之不存在运行期抛出异常。

    所有面向对象的编程都有类的概念,用于封装数据,这样的语言特性都有封装、继承和多态。OC对象是类在运行期的实例,包含了类声明的实例变量、内存拷贝、类成员的指针等。由于OC是C语言的超集,类由两个部分组成,分别是定义(interface)和实现(implementation),下面举个?。新建一个People类,@interface是接口声明的开始,@end终止结束,所有的OC编译指令都是以”@“开始的。类的实现是通过@implementation指令开头以@end结束。对应People.h和People.m两份文件,下图是类声明(People.h)的展示,主要包括继承关系、成员变量、属性、方法声明等,方法的具体实现是在People.m。
    在这里插入图片描述
    下图是方法声明的展示:
    在这里插入图片描述
    当然不止Interface区块可以定义变量,Implementation区块也可以定义,两者区别是访问权限不一。前者默认权限为protected,而implementation区块的实体变量则默认为private,所以类别私有可以放在implementation区块。

    访问修饰符

    • @public:任何位置可以访问。
    • @protected:默认情况下成员变量的修饰符。
    • @private:变量只限于声明它的类访问,不允许被继承。
    • @package:限定在当前包内,类似于Java包的概念。

    属性

    成员变量是给类内使用的,属性是作为类外访问成员变量的接口,用于封装对象的数据,通过@property声明,编译器自动生成setter和getter方法,此过程称为”自动合成“。类实现文件中@synthesize语法可以指定实例变量的名字,一般不推荐这样做。@dynamic语法是告诉编译器不要自动合成,在OC中访问修饰符很少用到,主要是靠声明属性取值。属性有五个常用的特质修饰:

    • assign:针对基本数据类型赋值操作。
    • strong:定义一种”拥有关系“,属性设置新值时,先保留新值,并释放旧值,然后再将新值设置。
    • weak:跟strong相反,属性所指的对象销毁时,属性值也会清空。
    • copy:设置方法不保留新值,而是拷贝一份。
    • nonatomic:非原子,非线程安全类型。

    Q&A:为什么NSString 、 NSArray、 NSDictionary的属性要用copy,集合的深浅拷贝是怎样的?
    copy属性作用是为变量赋值的时候系统自动copy一份内存出来,修改新变量不会影响旧变量。在Apple规范中,NSString,NSArray,NSDictonary,推荐使用copy属性,而其NSMubtableString,NSMutableArray, NSMutableDictonary属性则使用strong属性。

            NSString *sourceString = [NSString stringWithFormat:@"hello ios"];
            //不产生新的内存空间
            NSString *copyStr = [sourceString copy];
            //产生新的内存空间
            NSMutableString *mutableStr = [sourceString mutableCopy];
            NSLog(@"sourceString : %@   %p",sourceString,sourceString);
            NSLog(@"copyStr : %@    %p",copyStr,copyStr);
            NSLog(@"mutableStr : %@     %p",mutableStr,mutableStr);
    

    在这里插入图片描述
    使用strong这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。例如:

     	//代码块   
        NSMutableString *string = [NSMutableString stringWithString:@"origin"];//copy
        NSString *stringCopy = [string copy];
        NSLog(@"string address is: %p",string);
        NSLog(@"stringCopy address is: %p",stringCopy);
    

    结果:内存地址不同
    在这里插入图片描述

    		NSMutableString *string = [NSMutableString stringWithString:@"origin"];
    //        NSString *stringCopy = [string copy];
            NSString *stringCopy = string;
            [string appendString:@"change"];
            NSLog(@"string address is: %p",string);
            NSLog(@"stringCopy address is: %p",stringCopy);
    

    结果:内存地址相同
    在这里插入图片描述
    **结论:**可变对象指向不可变对象会导致不可变对象的值被篡改,所以需要copy属性。用@property声明NSString、NSArray、NSDictionary 经常使用copy关键字,是因为他们有对应的可变类型NSMutableString、NSMutableArray、NSMutableDictionary,彼此之间可能进行赋值操作,为了不可变对象中的内容不会被无意间变动,应该在设置新属性值时拷贝一份。
    浅拷贝:
    在Java中浅拷贝如果是基本数据,则拷贝的是基本数据的值;如果是对象,则拷贝的是内存地址,修改该对象会影响另外一个对象。在OC中是对指针的拷贝,拷贝后的指针和原本对象的指针指向同一块内存地址,故同样会相互影响。

    在这里插入图片描述
    深拷贝:
    OC中不仅拷贝指针,而且拷贝指针指向的内容,指针指向不同的内存地址,故修改不会相互影响原本对象。

    在这里插入图片描述
    非集合类对象中:对immutable对象进行copy操作,是指针复制(浅拷贝),mutableCopy操作时内容复制;对mutable对象进行copy和mutableCopy都是内容复制(深拷贝)。

    方法

    通过”+“、”-“分别声明类方法和实例方法,方法如果带有多个参数,参数在方法名之后接冒号定义,多个参数由空格隔开,如果参数个数可变,使用逗号接省略号。例如:

    //无参数
    - (void)print;
    //有参数
    - (void)print:(int)a andB:(int)b;
    

    构造方法

    第一种是重写init方法,第二种是自定义。

    /**
     重写初始化方法
     **/
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            _peopleName = @"hello ios";
        }
        return self;
    }
    
    /**
     自定义初始化方法
     **/
    - (instancetype)initWithNameAndAge:(NSString *)name andAge:(int)age
    {
        self = [super init];
        if (self) {
            _peopleName = name;
            _peopleAge = age;
        }
        return self;
    }
    

    创建类对象

    所有对象和类的引用都是通过指针实现,严格地说指针就是一个地址,是一个常量,而指针变量可以被赋值不同的指针值,创建的对象就是一个指针变量,通过[People alloc]创建一个People对象,分配了内存,init是初始化对象。构造方法有两种方式,第一种是重写init方法,第二种是自定义。

    People *p1 = [[People alloc] init];
    //调用自定义的构造方法
    People *p3 = [[People alloc] initWithNameAndAge:@"mingzi" andAge:12];
    //调用方法
    [p3 print];
    

    在OC 2.0中,如果创建的对象不需要参数,可以直接使用new:

    People *p1 = [People new];
    

    self

    作为OC的一个关键字,代表当前类的对象,类似Java中的this,最大的作用是让类中的一个方法调用该类另外一个方法或者成员变量,可以理解”当前类谁调用了这个方法,self就代表谁“。

    继承

    同Java一样只能单继承,只允许最多有一个直接父类。例如:定义一个父类Computer和子类MacBook。注意方法重写类似Java,子类要重写父类方法不需要重新声明重写方法,在实现部分直接重写目标方法即可。如果需要子类调用父类的方法,可以通过super关键字调用。

    //Computer.h文件
    #import <Foundation/Foundation.h>
    @interface Computer : NSObject
    @property(nonatomic,strong)NSString *name;
    -(void)calculate;
    @end
    
    //  Computer.m
    #import "Computer.h"
    @implementation Computer
    @synthesize name;
    -(void) calculate{
        NSLog(@"i can calculate");
    }
    @end
    
    //  MacBook.h
    #import "Computer.h"
    @interface MacBook : Computer
    @end
    
    //  MacBook.m
    #import "MacBook.h"
    @implementation MacBook
    @end
    
    //main.m
    int main(int argc, char *argv[])
    {
        @autoreleasepool
        {
            MacBook *macBook = [[MacBook alloc] init];
            macBook.name = @"mac";
            [macBook calculate];
        }
    }
    

    多态

    封装、继承和多态是面向对象编程语言的三大特性,OC的多态是不同对象对同一消息的不同响应方式,实际过程主要分为三种:

    1. 继承
    2. 重写
    3. 指向子类的指针指向父类

    可以看出跟Java的多态类似,理解起来应该比较容易,注意是没有方法重载的,在OC中不允许。

    Runtime

    实例:用Runtime新增一个类Person, person有name属性,有sayHi方法

    #import <UIKit/UIKit.h>
    #import "AppDelegate.h"
    #import <objc/runtime.h>
    #import <objc/message.h>
    void sayHi(id self, IMP _cmd, id some)
    {
        //self指的是调用该方法传过来的类
        NSLog(@"%@说:%@,我%@岁", [self valueForKey:@"name"], some, object_getIvar(self, class_getInstanceVariable([self class], "_age")));
    }
    
    int main(int argc, char *argv[])
    {
        @autoreleasepool
        {
            //该方法动态创建一个类,arg1:继承自哪个类 arg2:新建类的名称 arg3:extraBytes
            Class Person = objc_allocateClassPair([NSObject class], "Person", 0);
            //添加两个实例变量name和age,arg2:变量名称,arg3:内存地址大小,arg5:变量类型
            class_addIvar(Person, "_name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
            class_addIvar(Person, "_age", sizeof(int), sizeof(int), @encode(int));
            //注册方法名
            SEL s = sel_registerName("say:");
            //arg3:IMP是“implementation”的缩写,这个函数指针决定了最终执行哪段代码
            //arg4:方法的参数及返回值
            class_addMethod(Person, s, (IMP)sayHi, "v@:@");
            //通过该类创建一个实体的对象
            id peopleInstance = [[Person alloc]init];
            //给对象的 name 实例变量赋值,下面是第二种赋值方式
            [peopleInstance setValue:@"XQM" forKey:@"name"];
            //Ivar nameIvar = class_getInstanceVariable(Person, "_name");
            //object_setIvar(peopleInstance, nameIvar, @"XQM");
            //获取实例变量
            Ivar ageIvar = class_getInstanceVariable(Person, "_age");
            //为变量赋值
            object_setIvar(peopleInstance, ageIvar, @21);
            //调用sayHi方法,arg2:注册指定的方法;arg3:带上有一个字符串的参数
            ((void(*)(id, SEL, id))objc_msgSend)(peopleInstance, s, @"大家好");
            //调用完成,将对象置为空
            peopleInstance = nil;
            //通过 objc 销毁类,销毁的是一个类不是对象
            objc_disposeClassPair(Person);
        }
    }
    

    主要流程是:
    定义类的方法->objc_allocateClassPair创建类->class_addIvar给类添加成员变量->sel_registerName注册方法名->class_addMethod给类添加定义的方法->注册该类->创建类对象->class_getInstanceVariable获取成员变量,并通过object_setIvar赋值->objc_msgSend调用方法->释放对象,销毁类

    Category(类别)

    Objective-C借用并扩展了Smalltalk实现中的"分类"概念,用以帮助达到分解代码的目的。类别主要特点是不能增加属性或者成员变量、增加类功能和分离类实现,举个例子: 在UIImageView增加了图片异步加载的功能

    @interface UIImageView (ImageViewLoader) <AysncImageDownloaderDelegate>
    - (void)setOnlineImage:(NSString *)url placeholderImage:(UIImage *)image withRow:(NSNumber *)row;
    @end
    
    @implementation UIImageView (ImageViewLoader)
    
    - (void)setOnlineImage:(NSString *)url placeholderImage:(UIImage *)image withRow:(NSNumber *)row;
    {
        self.image = image;
        AsyncImageDownLoader *downloader = [AsyncImageDownLoader sharedImageDownloader];
        [downloader startWithUrl:url delegate:self withRow:row];
    }
    @end
    

    Extension(拓展)

    拓展也经常用到,主要特点是增加ivar、用于接口分离等。例如:ViewController的实现文件增加@interface ViewController (),支持定义属性等。

    @interface ViewController ()
    @property (nonatomic, copy) block b;
    @end
    
    @implementation ViewController
    @end
    

    异常处理

    OC的异常处理极其类似Java中的,包括4个指示符,分别是@try、@catch、@throw、@finally。可能存在异常的代码写在@try块,异常处理逻辑写在@catch,@finally块的代码总是要执行的,@throw作用是抛出异常。

    协议

    类似Java中的接口(interface),类似多重继承功能,支持协议继承协议,通过定义一系列方法,然后由遵从协议的类实现这些方法,协议方法可以用@optional关键字标记为可选,@required关键字标记为必选,编译器会出现检查警告,一般来说还是可以编译通过。下面看下语法:

    @protocol ClickDelegate
    - (void)click;
    - (void)unclick;
    @end
    

    协议最常应用在委托,分为委托方和代理方,委托方负责定义协议、通过id类型持有协议和调用协议的方法,而代理方则遵从协议、设置协议代理对象以及实现协议方法即可。

    block

    类似Java中的Lambda表达式,比较复杂,笔者的理解还未达到一定解说程度,所以这里先不做解释,放到后续的文章中介绍。

    内存管理

    Java的内存管理是由垃圾回收器负责,OC中引入自动引用计数(ARC),内存管理交由编译器决定。引用计数是每个对象都有一个计数器,如果对象继续存活,计数器递增其引用计数,用完之后递减引用计数,如果计数变为0,表示对象可以被释放了。NSObject协议声明了Retain、release和autorelease方法用于操作计数器,分别是递增、递减、自动释放操作,所有的对象都是收集器的工作对象。

    ARC:自动引用计数,编译器自动生成retain/release
    MRC:手动管理引用计数,旧版本使用
    autoreleasepool:延迟自动释放

    strong/weak/assgin最佳实践

    • 基本类型:assgin;
    • delegate->week;
    • 集合和block用copy;
    • 其他用strong;
    • block中的self用weak打破循环引用。

    参考资料

    1. https://www.jianshu.com/p/eb713b1f22dc
    2. https://www.jianshu.com/p/6ebda3cd8052
    3. https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html
    展开全文
  • Objective-C入门教程01:使用Xcode新建一个工程 一、objective-c简介:  Xcode 是 Apple 的集成开发环境,用于 iOS 和 Mac OS X 的开发。Xcode可以直接在App Store中安装,也可以从网络下载或是拷贝过来安装。...

    Objective-C入门01:使用Xcode新建一个工程


    一、objective-c简介:
        Xcode 是 Apple 的集成开发环境,用于 iOS 和 Mac OS X 的开发。Xcode可以直接在App Store中安装,也可以从网络下载或是拷贝过来安装。在 Mac 上安装 Xcode,也会同时安装了 iOS SDK,它包含 iOS 平台的编程接口。


    二、新建项目:

       Xcode启动Xcode后,会显示欢迎画面

       在界面中单击Create a new Xcode  project项后,进入创建新工程的导航窗口(右边的是最近打开过的项目,点击即可打开对应项目)



       ②窗口中显示了所有工程模板列表,在左侧的分类导航窗口的上方可选择 iOS 和 OS X 应用程序的模板。由于我们现在只是学习OC的语法,所有只需选择 OS X 下的 Application → Command Line Tool,单击Next按钮,



    ③在这个页面中 填写时需要注意的是:

    Product Name :  项目名称 (不能为中文);

    Organization Name : 公司名称

    Organization Identifier : 唯一标识(真机调试时使用)(AppStore里的唯一身份)

    Bundle Identifier : 生成唯一的标识;

    language: 编程语言(Oc是对C语言的封装,swift是苹果专用的编程语言);

    点击 Next 按钮 在弹出的对话框中选择项目保存的路径后,单击Save按钮,新工程创建成功。






    三、Xcode 界面详解

      1.Xcode 界面简介



         

       ①顶部区域

     程序运行相关 :从左至右介绍 : 运行按钮, 停止按钮, 为工程选择运行平台;


       

        面板控制相关:  从左至右介绍 : 隐藏左侧面板, 隐藏底部面板, 隐藏右侧面板;


        

         左侧区域 该面板是 Xcode 工程导航面板, 上方的七个按钮用于切换导航模式;



        ③底部面板:用于 Xcode 显示 控制台调试输出信息;



        ④右面板

    检查器面板 根据项目的不同, 包含大量审查器;



    库面板简介(从左至右) : 文件模板库, 代码片段库, 对象库, 媒体库;



    ⑤详细编辑区:该区域是代码编写主要区域 




    2、导航面板详解

    导航面板简介 从左至右 : 项目导航, 符号导航, 搜索导航, 问题导航, 测试导航, 调试导航, 断点导航, 日志导航;



       ①项目导航


    项目导航组成 :  

    -- 源文件 : 在 HelloWorld 目录下的 ".h" 和 ".m" 后缀文件是源文件; 

    -- 属性文件 : 在 HelloWorld 下的 Supporting Files 目录下是属性文件 图片等; 

    -- 单元测试项目 : HelloWorldTest 是工程的单元测试项目; 

    -- 目标应用 : Products 目录下的 HelloWorld.app 是目标应用;


       ②项目导航


    符号导航简介 : 用符号显示工程中的 类, 项目 和 属性; 

    -- 表示方式 : C 表示类, M 表示方法, P 表示属性; 

    -- 快速定位 : 点击对应的方法或者属性, 能快速定位到这个类中;


       ③搜索导航

           搜索导航简介 : 在搜索框中输入要搜索的字符串, 按回车就可以搜索出包含该字符串的类;




       ④问题导航面版

           问题导航面板简介 : 显示项目中存在的警告或者错误;



        ⑤测试导航
    测试导航简介   : 点击 testExample 后面的执行按钮, 就会运行该单元测试;



       ⑥调试导航

           调试导航简介 : 调试导航面板中显示了设备的详细信息 ( cpu使用情况,内存等 );



       ⑦断点导航

     断点导航简介 : 列出所有的断点, 方便管理断点;



         ⑧日志导航
    日志导航简介 : 列出项目开发过程中 构建, 生成, 运行过程, 每次该过程都可以通过日志面板查看;

















    展开全文
  • Objective-C 入门教程

    千次阅读 2016-12-13 12:54:14
    来自 ...Objective-C 通过提供类定义,方法以及属性的语法,还有其他可以提高类的动态扩展能力的结构等,扩展了标准的 ANSI C 语言。类的语法和设计主要是基于 Smalltalk,最早的面向对象编程语言
  • C入门: 高低位检测函数及int转char[4]

    千次阅读 2011-08-03 16:35:31
    C入门 高低位检测函数 int转char[4]
  • int x = threadIdx.x+blockIdx.x*blockDim.x; int y = threadIdx.y+blockIdx.y*blockDim.y; int z = threadIdx.z+blockIdx.z*blockDim.z; int offset=(z*blockDim.y*gridDim.y+y)*blockDim.x*gridDim.x+x;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 51,483
精华内容 20,593
关键字:

c入门