顯示具有 ObjectC 標籤的文章。 顯示所有文章
顯示具有 ObjectC 標籤的文章。 顯示所有文章

2014年4月8日 星期二

xcode自我判定錯誤,所產生的自我迴圈。

1. xxx.h設定一個變數

@property (nonatomic) BOOL deleteMP;




2. xxx.m 不小心寫了一個 包含這個變數的呼叫函數,此處xcode會自行判定為設定呼叫
- (void) setDeleteMP:(int)winPoints
{
    if (self.replaceMP!= YES && self.isFrame == NO) {
        self.deleteMP = YES;
        self.winPoints = winPoints;
}




3. 然後在其他某處使用了

xxx.deleteMP = YES;



4. 於是形成了一個自我迴圈,不斷呼叫 setDeleteMP。
很有趣的一個錯誤產生,居然是xcode的自我判定錯誤,而這個錯誤雖然很容易抓,還是寫出來當作以後的警戒。

2014年1月1日 星期三

NSMutableArray 不可作為Class來使用

官方文件上的說明

Subclassing Notes
There is typically little reason to subclass NSMutableArray. The class does well what it is designed to do—maintain a mutable, ordered collection of objects. But there are situations where a custom NSArray object might come in handy. Here are a few possibilities:

Changing how NSMutableArray stores the elements of its collection. You might do this for performance reasons or for better compatibility with legacy code.
Acquiring more information about what is happening to the collection (for example, statistics gathering).
Methods to Override

NSMutableArray defines five primitive methods:

insertObject:atIndex:
removeObjectAtIndex:
addObject:
removeLastObject
replaceObjectAtIndex:withObject:


In a subclass, you must override all these methods. You must also override the primitive methods of the NSArray class.




因為有這些method影響了作為Class的設定,因此需要覆寫原有的method才能使用,否則會產生錯誤。使用上太過麻煩,因此不建議使用NSMutableArray來作為class使用。


2013年6月5日 星期三

Xcode 上可參考使用的math library


1. oolongengine

Logo

http://code.google.com/p/oolongengine/

The Oolong Engine is written in C++ with some help from Objective-C. It will help you to create new games and port existing games to the iPhone, the iPod touch and the iPad. Here is its feature list:
  • OpenGL ES 1.1 and OpenGL 2.0 (> iPhone 3GS, iPod touch third gen, iPad) support
  • Math library that supports floating-point calculations with an interface very similar to the D3D math library
  • Support for numerous texture formats including the PowerVR 2-bit, 4-bit and normal map compression formats
  • Support for PowerVR's POD (Scene and Meshes), .3DS and .blend file formats
  • Touch screen support
  • Accelerometer support
  • Text rendering to support a basic UI
  • Timing: several functions that can replace rdstc, QueryPerformance etc.
  • Profiler: industry proven in-game profiler
  • Resources streaming system
  • Bullet SDK support (for 3D Physics)
  • Audio engine with OpenAL support
  • Networking with the ENet library
  • Industry proven memory manager from http://www.fluidstudios.com

2013年5月20日 星期一

OpenGLES on IOS (二)

整理一下整個OPENGLES在IOS上實做過程的資料

參考網頁
http://blog.csdn.net/kesalin/article/details/8223649
http://blog.csdn.net/kesalin/article/details/7168967


實作紀錄網頁
http://kirenenko-tw.blogspot.tw/2013/04/opengl_11.html


1. 首先使用 initWithCoder 初始化 Storyboard 上的元件(OpenGLView.m)

initWithCoder 是物件既有的一個初始化方法函式,正常來說,你不會在使用程式碼動態產生物件時去呼叫它產生新的物件,而是在使用 Storyboard 設計介面時,直接將 Storyboard 上的元件與類別中的 initWithCoder 方法做連結,使用類似靜態的方式,讓應用程式在一開始執行時就將介面上的元件直接定義成該類別。

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setupLayer];     // 初始設定 一個 CAEAGLLayer


        [self setupContext];    // 初始設定一個 rendering context

        [self setupProgram];  // 載入shader的執行程式碼 ,最重要的主程式

        [self setupProjection];  //設定投射矩陣
     
        [self resetTransform];  // 回歸初始值
       
    }
   
    return self;
}





OpenGL ES是Core Animation的客户,要使用OpenGL ES需要创建一个UIView,这个UIView由一个特殊的core animation layer支持,这个特殊的layer是一个CAEAGLLayer对象。CAEAGLLayer是OpenGLES和core animation联系的桥梁。当应用程序渲染完一帧后,CAEAGLLayer的内容被呈现并且和其他view的数据组合。


參考網頁 http://hi.baidu.com/wwssttt/item/e161f725e2ba9941469962d3

- (void)setupLayer
{
    _eaglLayer = (CAEAGLLayer*) self.layer;
   
    // CALayer 默认是透明的,必须将它设为不透明才能让其可见
    _eaglLayer.opaque = YES;
   
    // 设置描绘属性,在这里设置不维持渲染内容以及颜色格式为 RGBA8
    _eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
}




EAGLContext : 定义了rendering context。应用程序创建和初始化一个EAGLContext,设定他为当前的OpenGL命令的目标。OpenGL命令通常存放在一个 context所维护的队列里面,并在之后被执行。EAGLContext也提供了方法将图像呈现给Core Animation。

- (void)setupContext {
    // 指定 OpenGL 渲染 API 的版本,在这里我们使用 OpenGL ES 2.0
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
    _context = [[EAGLContext alloc] initWithAPI:api];
    if (!_context) {
        NSLog(@" >> Error: Failed to initialize OpenGLES 2.0 context");
        exit(1);
    }
   
    // 设置为当前上下文
    if (![EAGLContext setCurrentContext:_context]) {
        _context = nil;
        NSLog(@" >> Error: Failed to set current OpenGL context");
        exit(1);
    }
}




在前面提到可编程管线通过用 shader 语言编写脚本文件实现的,这些脚本文件相当于 C 源码,有源码就需要编译链接,因此需要对应的编译器与链接器,shader 对象与 program 对象就相当于编译器与链接器。shader 对象载入源码,然后编译成 object 形式(就像C源码编译成 .obj文件)。经过编译的 shader 就可以装配到 program 对象中,每个 program对象必须装配两个 shader 对象:一个顶点 shader,一个片元 shader,然后 program 对象被连接成“可执行文件”,这样就可以在 render 中是由该“可执行文件”了。 

參考網頁 http://content.gpwiki.org/index.php/OpenGL:Tutorials:Loading_and_using_GLSL_shaders#Creating_the_Program



- (void)setupProgram
{
    // Load shaders
    //
   
    NSString * vertexShaderPath;
    NSString * fragmentShaderPath;
   
    vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"VertexShader"
                                                       ofType:@"glsl"];
    fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader"
                                                         ofType:@"glsl"];
 
   
   
    //從 加入 shader,此處的
loadProgramg需自己處理   
_programHandle = [GLESUtils loadProgram:vertexShaderPath
                 withFragmentShaderFilepath:fragmentShaderPath];
    if (_programHandle == 0) {
        NSLog(@" >> Error: Failed to setup program.");
        return;
    }
   
    glUseProgram(_programHandle);
   
    // Get the attribute position slot from program
    // 通过调用 glGetAttribLocation 我们获取到 shader 中定义的变量 vPosition 在 program 的槽位,通过该槽位我们就可以对 vPosition 进行操作。
    // Returns the location of an attribute variable
    _positionSlot = glGetAttribLocation(_programHandle, "vPosition");
   
    // Get the uniform model-view matrix slot from program
    //  Returns the location of a uniform variable
    _modelViewSlot = glGetUniformLocation(_programHandle, "modelView");

   
    // Get the uniform projection matrix slot from program
    //
    _projectionSlot = glGetUniformLocation(_programHandle, "projection");
   
}




 



其中會用到兩隻檔案
VertexShader.glsl  及  FragmentShader.glsl





VertexShader.glsl
uniform mat4 projection;
uniform mat4 modelView;
attribute vec4 vPosition;


void  main(void)
{
    gl_Position = projection * modelView * vPosition;
}


FragmentShader.glsl

precision mediump float;

void main()
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}


此處要說明一下


Uniforms and Attributes

Uniforms 是一个program 中统一分配的,vertext 和fragment中同名的Uniform必须同类型。对应于不经常变化的变量。

Attributes 变化率高的变量。主要用来定义输入的每次点属性。

Uniforms and Attributes 在shader中通过location 和 name 来对应的。

通过GLint glGetUniformLocation(GLuint program,const char* name).根据一个Uniform的名称获取其location. 通过 glUniform***系列函数可以给一个location 设置一个Uniform的值。

參考網頁  http://blog.csdn.net/beelike/article/details/5774288


對於 loadProgram,可將其放在外部檔案,此例放在GLESUtils.m
+(GLuint)loadProgram:(NSString *)vertexShaderFilepath withFragmentShaderFilepath:(NSString *)fragmentShaderFilepath
{
    // Load the vertex/fragment shaders, and compile,此處的
loadShader也需要自己處理  
// shader type => GL_VERTEX_SHADER
    GLuint vertexShader = [self loadShader:GL_VERTEX_SHADER
                              withFilepath:vertexShaderFilepath];
    if (vertexShader == 0)
        return 0;
   
    // shader type => GL_FRAGMENT_SHADER
    GLuint fragmentShader = [self loadShader:GL_FRAGMENT_SHADER
                                withFilepath:fragmentShaderFilepath];
    if (fragmentShader == 0) {
        glDeleteShader(vertexShader);
        return 0;
    }
   
    // Create the program object
    GLuint programHandle = glCreateProgram();
    if (programHandle == 0)
        return 0;
   
    glAttachShader(programHandle, vertexShader);
    glAttachShader(programHandle, fragmentShader);
   
    // Link the program
    glLinkProgram(programHandle);
   
    // Check the link status
    GLint linked;
    glGetProgramiv(programHandle, GL_LINK_STATUS, &linked);
   
    if (!linked) {
        GLint infoLen = 0;
        glGetProgramiv(programHandle, GL_INFO_LOG_LENGTH, &infoLen);
       
        if (infoLen > 1){
            char * infoLog = malloc(sizeof(char) * infoLen);
            glGetProgramInfoLog(programHandle, infoLen, NULL, infoLog);
           
            NSLog(@"Error linking program:\n%s\n", infoLog);
           
            free(infoLog);
        }
       
        glDeleteProgram(programHandle );
        return 0;
    }
   
    // Free up no longer needed shader resources
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
   
    return programHandle;
}
 


+(GLuint)loadShader:(GLenum)type withFilepath:(NSString *)shaderFilepath
{
    NSError* error;
    NSString* shaderString = [NSString stringWithContentsOfFile:shaderFilepath
                                                       encoding:NSUTF8StringEncoding
                                                          error:&error];
    if (!shaderString) {
        NSLog(@"Error: loading shader file: %@ %@", shaderFilepath, error.localizedDescription);
        return 0;
    }
   
    return [self loadShader:type withString:shaderString];
}

+(GLuint)loadShader:(GLenum)type withString:(NSString *)shaderString
{
    // Create the shader object
    GLuint shader = glCreateShader(type);  //
    if (shader == 0) {
        NSLog(@"Error: failed to create shader.");
        return 0;
    }
   
    // Load the shader source
    const char * shaderStringUTF8 = [shaderString UTF8String];
    glShaderSource(shader, 1, &shaderStringUTF8, NULL);
   
    // Compile the shader
    glCompileShader(shader);
   
    // Check the compile status
    GLint compiled = 0;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
   
    if (!compiled) {
        GLint infoLen = 0;
        glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
       
        if (infoLen > 1) {
            char * infoLog = malloc(sizeof(char) * infoLen);
            glGetShaderInfoLog (shader, infoLen, NULL, infoLog);
            NSLog(@"Error compiling shader:\n%s\n", infoLog );
           
            free(infoLog);
        }
       
        glDeleteShader(shader);
        return 0;
    }
   
    return shader;
}
 


基本shader創建的步驟,但是省略了檢查錯誤的步驟,實作上卻是必要的。
1. glCreateShader创建着色器对象

2. glShaderSource为着色器加载源代码,讀入檔案

3. glCompileShader编译每个着色器

4. glCreateProgram创建程序对象



5. glAttachShader 把着色器对象连接到程序对象

6. glLinkProgram 链接程序对象,生成可执行程序

7. glUseProgram安装可执行程序替换OpengGL固定功能流水线处理模块








設定投影矩陣
此處可參考網頁 http://kirenenko-tw.blogspot.tw/2013/05/opengl_16.html,瞭解整個投影的需求。 
-(void)setupProjection
{
    // Generate a perspective matrix with a 60 degree FOV
    //
    float aspect = self.frame.size.width / self.frame.size.height;  // 目前的畫面是投射近距離的畫面,要觀察遠距離的畫面。
    ksMatrixLoadIdentity(&_projectionMatrix);
   
    // 使用一個單元矩陣來產生一個投射的矩陣
    ksPerspective(&_projectionMatrix, 60.0, aspect, 1.0f, 20.0f);

   
    // Load projection matrix
    glUniformMatrix4fv(_projectionSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
    ///glUniformMatrix4fv函数用我们得到的变换矩阵来更新着色器程序里的uniform变量矩阵modelview。第一个参数是要修改的uniform变量的索引位置,第二个参数是要修改的矩阵数据,这里是1个。第三个参数是第四个参数是按行主序还是列主序指定的,这里我们用GL_FALSE(0),表明是列主序指定的,矩陣不需要轉置。最后一个参数是我们前面设定的变换矩阵。  
}



- (void)resetTransform
{
    if (_displayLink != nil) {
        [_displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        _displayLink = nil;
    }

    self.posX = 0.0;
    self.posY = 0.0;
    self.posZ = -5.5;
   
    self.rotateX = 0.0;
    self.rotateY = 0.0;
    self.scaleZ = 1.0;
   
    [self updateTransform];
}
 


// 重新計算所有modelView的對應矩陣
- (void)updateTransform
{
    // Generate a model view matrix to rotate/translate/scale
    //
    ksMatrixLoadIdentity(&_modelViewMatrix);
   
    // Translate away from the viewer
    //
    ksMatrixTranslate(&_modelViewMatrix, self.posX, self.posY, self.posZ);
   
    // Rotate the triangle
    //
    ksMatrixRotate(&_modelViewMatrix, self.rotateX, 1.0, 0.0, 0.0);  // rotate X
   
    ksMatrixRotate(&_modelViewMatrix, self.rotateY, 0.0, 1.0, 0.0);  // rotate Y
   
   
    // Scale the triangle
    ksMatrixScale(&_modelViewMatrix, 1.0, 1.0, self.scaleZ);
   
    // Load the model-view matrix,將
modelViewMatrix載入到_modelViewSlot中
     glUniformMatrix4fv(_modelViewSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
}
 


2. 一旦有所需要,就開始繪圖,此處包含在render內


- (void)render
{
    if (_context == nil)
        return;
   
    glClearColor(0, 1.0, 0, 1.0);  // specify clear values for the color buffers
    glClear(GL_COLOR_BUFFER_BIT);  //  clear buffers to preset values, The three masks are GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, and GL_STENCIL_BUFFER_BIT.
   
    // Setup viewport
    //
    glViewport(0, 0, self.frame.size.width, self.frame.size.height); // glViewport 表示渲染 surface 将在屏幕上的哪个区域呈现出来
   
    [self drawCube];  // 劃出方形磚塊
   
    [_context presentRenderbuffer:GL_RENDERBUFFER];  // Displays a renderbuffer’s contents on screen.
}

3. 使用layoutSubviews來繪製畫面,這是一個類似重畫的機制,

可參考 http://kirenenko-tw.blogspot.tw/2013/04/layoutsubviews.html


- (void)layoutSubviews
{
    [EAGLContext setCurrentContext:_context];  // The graphics-context object to set as the current one. This must be an instance of a concrete subclass of NSGraphicsContext.
   
    glUseProgram(_programHandle);  // Installs a program object as part of current rendering state
   
    [self destoryBuffers];
   
    [self setupBuffers];
        


    // 任何目標的轉移與縮放,基本上都只用到下面兩個函數呼叫  
    [self updateTransform];
    [self render];

}



- (void)destoryBuffers
{
    glDeleteRenderbuffers(1, &_colorRenderBuffer);
    _colorRenderBuffer = 0;
   
    glDeleteFramebuffers(1, &_frameBuffer);
    _frameBuffer = 0;
}



- (void)setupBuffers {
    glGenRenderbuffers(1, &_colorRenderBuffer); // Specifies an array in which the generated renderbuffer object names are stored.
   
   
    // 设置为当前 renderbuffer
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
    // bind a renderbuffer to a renderbuffer target
   
   
    // 为 color renderbuffer 分配存储空间
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
    // Binds a drawable object’s storage to an OpenGL ES renderbuffer object.
   
   
    glGenFramebuffers(1, &_frameBuffer); //
    //  Specifies an array in which the generated framebuffer object names are stored.
   
    // 设置为当前 framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    //bind a framebuffer to a framebuffer target
   
   
    // 将 _colorRenderBuffer 装配到 GL_COLOR_ATTACHMENT0 这个装配点上
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                              GL_RENDERBUFFER, _colorRenderBuffer);
    //attach a renderbuffer as a logical buffer to the currently bound framebuffer object
   
   
}




整個程序到此,可以繪出一個3D的Model。如果有任何Model上的變化,只需要用到下面兩行就可以了。

// 任何目標的轉移與縮放,基本上都只用到下面兩個函數呼叫  
    [self updateTransform];
    [self render];








 






2013年4月15日 星期一

objectC++的使用

首先要先瞭解Xcode下的檔案格式

XCode中使用副檔名來判斷程式使用的語言是 C 或是 C++,Objective-C的檔案可以使用以下副檔名:
副檔名
說明
h
標頭檔,或稱定義檔或是介面檔。標頭檔包含了類別、變數、方法和常數的宣告。
m
實作檔,編譯器 將 .m檔視為使用C語言實作,在.m檔中可以混用Objective-C 和 C語言的語法。
mm
實作檔,編譯器 將 .mm 檔視為使用 C++語言實作,在.mm檔中可以混用Objective-C 和 C++ 語言的語法。


使用時機
通常只有為了和原有的C++程式或是C++函數庫整合時才會使用Objective-C++,一般來說iPhone的程式開 發仍是以Objective-C為主。例如加入一個Cpp的檔案。


副檔名為mm
在Xcode下先產生.m檔,基本上我都是使用Template,可同時產生.h及.m檔,參考下圖

 然後再修改副檔名為mm就可以了。

在Project中會自動辨識及修正



 
如果副檔名沒改會產生一連串奇怪的錯誤,因為不認識C++的語法,例如


如果平常開發時有使用到C++的程式碼,然後又出現有奇怪的Compile錯誤,只要將有用到檔名為.m的都改成.mm(如 main.m ==> main.mm ...),就可以解決了。


2012年12月11日 星期二

NSObject參考資料

class NSObject 是所有 Objective-C 類別的 Super-Class.
class NSObject 的命名方式, 名稱前方有 NS 代表的是 NeXTStep 作業系統,
這是一套由 NeXT.Inc 公司所開發的作業系統, 目前 NeXTStep 作業系統已經賣掉了,
也已經更名為 OpenStep 作業系統.

由於, Mac OS 的官方API, Cocoa API 前身就是 NeXTStep 的 API, 所以, 舊有的
Cocoa API 都是以 NS 為開頭, 也都是使用 Objective-C 寫成的, 目前這些舊有 class
也仍然保留 NS 為 class 的 Pre-fix 開頭.

其他資料可參考
http://rritw.com/a/caozuoxitong/OS/20111106/140088.html


2012年10月30日 星期二

NSNumber的使用


簡當整理一下NSNumber的使用
NSNumber提供一個機制,將數值用Class包裝起來,給NSArray之類來做儲存。


1. int/float/double ...變數與NSNumber的互轉


int result = [MyNsNumber intValue]; // NSNumber to be int


NSNumber number = [NSNumber numberWithInt:10]; // int to NSNumber;



2. init的設定方法
NSNumber *intNumber = [[NSNumber alloc] initWithInt:100];

NSNumber *floatNumber = [[NSNumber alloc] initWithFloat:99.9];

NSNumber *doubleNumber = [[NSNumber alloc] initWithDouble:100.0];

NSNumber *charNumber = [[NSNumber alloc] initWithChar:'T'];

NSNumber *boolNumber = [[NSNumber alloc] initWithBool:TRUE];


配製定義的最大/最小值

NSNumber* intNumber2 = [NSNumber numberWithInt:INT_MAX];

NSNumber* floatNumber2 = [NSNumber numberWithFloat:FLT_MIN];

NSNumber* doubleNumber2 = [NSNumber numberWithDouble:DBL_MAX];



3.比對方法
基本上我是將值轉換成int/float一般的數值變數再去做比較,但是NSNumber也是有提供比對機制


[intNumber isEqualToNumber: floatNumber]
使用isEqualToNumber:方法根据数值比较两个NSNumber对象。该程序测试返回的Boolean值,以查看这两个值是否相等。

可用compare:方法来测试一个数值型的值是否在数值上小于、等于或大于另一个值。消息表达式

[intNumber compare: myNumber]
在 intNumber中的值小于myNumber中的值时,返回值NSOrderedAscending;如果这两个数相等,则返回值 NSOrderedSame;如果第一个值大于第二个值,则返回值NSOrderedDescending。在头文件NSObject.h中已经定义了这 些返回值。




2012年10月17日 星期三

switch case的基本使用

在objectC中如果有需要用到c++ 中的 case用法,可參考下面基本使用例

原始描述
switch(expression or variable)
{
     case value1:
          // Program statement
          // Program statement
          ...
          break;
     case value2:
          // Program statement
          // Program statement
          ...
          break;
     case value3:
          // Program statement
          // Program statement
          ...
          break;
     ...
     case valueN:
          // Program statement
          // Program statement
          ...
          break;
     default:
          // Program statement
          // Program statement
          ...
          break;
}


例子
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    switch (section) {
        case 0:
            return @"鮮花";
            break;
           
        case 1:
            return @"水果";
            break;
           
        default:
            return @"";
            break;
    }
}

另一例
NSString *operator = [[NSString alloc] init];     // We will talk in depth about NSString later on down the road.
 // Assume operator has been initialized to a valid value
 // Valid values for operator are @"+", @"-", @"*", and @"/"

 switch (operator) {
  case @"+":
   NSLog(@"Operator is for addition.");
   break;
  case @"-":
   NSLog(@"Operator is for subtraction.");
   break;
  case @"*":
   NSLog(@"Operator is for multiplication.");
   break;
  case @"/":
   NSLog(@"Operator is for division.");
   break;
  default:
   NSLog(@"Unknown operator.");
   break;
 }
 
以上就相當於
NSString *operator = [[NSString alloc] init];
 // Assume operator has been initialized to a valid value
 // Valid values for operator are @"+", @"-", @"*", and @"/"

 /* Note that NSString actually has a comparison method, and that
    this method of comparison is not guaranteed to work. We are
    overlooking that at the moment for the sake of education. */
 if (operator == @"+")
  NSLog(@"Operator is for addition.");
 else if (operator == @"-")
  NSLog(@"Operator is for subtraction.");
 else if (operator == @"*")
  NSLog(@"Operator is for multiplication.");
 else if (operator == @"/")
  NSLog(@"Operator is for division.");
 else
  NSLog(@"Unknown operator.");   

2012年10月16日 星期二

objectC下的亂數取用

參考: http://www.cnblogs.com/xuling/archive/2012/02/28/2370692.html

在Xcode經常需要使用到亂數來取隨意值變化,基本上有三種選擇


1)、arc4random() 比較精確不需要生成隨即種子
使用方法 :
通過arc4random() 獲取0到x-1之間的整數的代碼如下:
int value = arc4random() % x;

獲取1到x之間的整數的代碼如下:
int value = (arc4random() % x) + 1;

浮點數取值
#define ARC4RANDOM_MAX      0x100000000

Then, you can use arc4random() to get a floating point value (at double the precision of using rand()), between 0 and 100, like so:
double val = floorf(((double)arc4random() / ARC4RANDOM_MAX) * 100.0f);





arc4random,它就藏在C语言标准库(Standard C Library)当中.文档对于它的描述是:
The arc4random() function uses the key stream generator employed by the arc4 cipher, which uses 8*8 8 bit S-Boxes. The S-Boxes can be in about (21700) states. The arc4random() function returns pseudo-random numbers in the range of 0 to (232)-1, and therefore has twice the range of rand(3) and random(3) .
arc4random既使用了arc4加密算法避免seed重复,并且比random的取值范围(2**31)-1整整大了一倍



在iPhone中,RAND_MAX是0x7fffffff (2147483647),而arc4random()返回的最大值则是 0×100000000 (4294967296),从而有更好的精度。此外,使用arc4random()还不需要生成随机种子,因为第一次调用的时候就会自动生成。


2)、CCRANDOM_0_1() cocos2d中使用 ,範圍是[0,1]
使用方法:
float random = CCRANDOM_0_1() * 5; //[0,5] CCRANDOM_0_1() 取值範圍是[0,1]

網路上的有資料說明  這是一個random的定義微碼
#define CCRANDOM_0_1() ((random() / (float)0x7fffffff ))



所以
int i = CCRANDOM_0_1();
 
==> int i =  ((random() / (float)0x7fffffff ));
 






3)、random() 需要初始化時設置種子
使用方法:
srandom((unsigned int)time(time_t *)NULL); //初始化時,設置下種子就好了。




補充資料,arc4random有一些變形的函數可用。

ARC4RANDOM(3)            BSD Library Functions Manual            ARC4RANDOM(3)

NAME
     arc4random, arc4random_buf, arc4random_uniform, arc4random_stir, arc4random_addrandom -- arc4 random number generator

LIBRARY
     Standard C Library (libc, -lc)

SYNOPSIS
     #include <stdlib.h>

     u_int32_t
     arc4random(void);

     void
     arc4random_buf(void *buf, size_t nbytes);

     u_int32_t
arc4random_uniform(u_int32_t upper_bound);

arc4random_uniform(74); // [0, 74)


     void
     arc4random_stir(void);

     void
     arc4random_addrandom(unsigned char *dat, int datlen);

DESCRIPTION
     The arc4random() function uses the key stream generator employed by the arc4 cipher, which uses 8*8 8 bit S-Boxes.  The S-Boxes can be in about (2**1700) states.
     The arc4random() function returns pseudo-random numbers in the range of 0 to (2**32)-1, and therefore has twice the range of rand(3) and random(3).

     arc4random_buf() function fills the region buf of length nbytes with ARC4-derived random data.

     arc4random_uniform() will return a uniformly distributed random number less than upper_bound.  arc4random_uniform() is recommended over constructions like
     ``arc4random() % upper_bound'' as it avoids "modulo bias" when the upper bound is not a power of two.

     The arc4random_stir() function reads data from /dev/urandom and uses it to permute the S-Boxes via arc4random_addrandom().

     There is no need to call arc4random_stir() before using arc4random() functions family, since they automatically initialize themselves.

EXAMPLES
     The following produces a drop-in replacement for the traditional rand() and random() functions using arc4random():

           #define foo4random() (arc4random() % ((unsigned)RAND_MAX + 1))

SEE ALSO

HISTORY
     RC4 has been designed by RSA Data Security, Inc.  It was posted anonymously to the USENET and was confirmed to be equivalent by several sources who had access to the
     original cipher.  Since RC4 used to be a trade secret, the cipher is now referred to as ARC4.

BSD                             April 15, 1997                             BSD



Xcode下使用範例
在UIView下使用一個Button及Label

然後使用一個IBAction如下,就會得到變數,1~6
- (IBAction)getRandom:(id)sender {
   
    int value = arc4random() % 6 +1;
   
    numLabel.text = [NSString stringWithFormat:@"%d",value];
   
}

網路上有人已經有一個例子可供參考
http://divakalife.blogspot.tw/2011/01/iphone-app-random-number.html

2012年7月21日 星期六

heap and stack


堆疊(Stack)和堆積(Heap)

堆(heap)和堆棧(stack)

兩種中文譯法不同

 

先參考: windows的 stack、heap記憶體(內存)管理重點筆記

 http://iambigd.blogspot.tw/2009/12/windows-stackheap.html

stack: 何謂stack? 是用來放function上auto級的變數(這樣的說法較專業),所謂auto級的就是變數是宣告在function內,它的生命(life time/ extent)在function結束後就無效了! stack的大小是由 linker來決定,以bcb為例,最大可以到0x1000000,即約16MB,你可以在project option上改。由多程式人員喜歡把object放在stack上,即用下面的宣告方式
ClassT object; 這樣整個object的資料都會配在stack上,若class小還好,大則容易overflow。故一般建議用new的方式來create objcet,只留下4byte的指標在stack上。


heap: 是用來動態使用記憶體的方式,使用的自由度最高,但需要自行善後清理。通常是用malloc/free或是new/delete來處理。heap在 windows下可以分為二種,1為default heap2為dynamic heap。default heap 可以是windows dll 等api使用,也可以app自己使用。我們開發的ap是如何來使用這個default heap呢? 可透過下面的三個api來使用GlobalAlloc 或 LocalAlloc 或GetProcessHeap來使用。事實上這個heap還再細分為fixed和movable二種。一般我們都是使用fixed。而vc++的 malloc等c run time就是用這個default heap。這個default heap的大小限制為何? 這是一個很重要的題目。另一種heap稱為 dynamic heap,這個heap就全然是我們的ap自由使用的地方。它和default heap有個不同? dynamic heap 全都是自己程式用,沒有別的api使用,另外還有一個重要的地方是這個heap可以控制多緒(multithread)同步共享heap的管理。可由 HeapCreate等相關api還有VirtualXxx api來建立。bcb本身的malloc等c run time 聽說是使用這種heap,與vc++有所不同。


另可參考
http://antrash.pixnet.net/blog/post/70456505-stack-vs-heap%EF%BC%9A%E5%9F%B7%E8%A1%8C%E6%99%82%E6%9C%9F%E5%84%B2%E5%AD%98%E5%85%A9%E5%A4%A7%E8%A6%81%E8%A7%92

有較詳細的說明

可預測性外加後進先出的生存模式,令stack無疑是最佳的存放策略。由於程式語言中變數跟函式的生命週期皆為後進先出的概念,也就是越晚產生的會越先被回收或銷毀。正因如此只要是可預測性的相關資訊都是往stack存放。此外,由於stack中的資料之存活週期規律故由系統自行產生與回收其空間即可,就不勞工程師們費心啦!

天啊!程式中竟然有不可預測其存活時間的資料存在。在程式中,有部分的需求總是在執行中依據實際情況才會動態增減,這些資訊是難以被預測哪時候開始有?量有多少?何時該回收?這些不可預測的因素造成上述的stack區塊不適合運用於此。當資訊為動態配置產生,系統會存放在另外一塊空間,稱之為『Heap(注意這裡的Heap跟資料結構中的Heap不相關,可別會錯意!)Heap的區塊專收執行期間動態產生的資料,由於為動態產生故結束點無法由系統來掌握,故需使用者自行回收空間。在C++Java中利用new語法產生的就是動態配置的物件,需存放於heap中。

奇怪跑越久記憶體用越多的怪現象。許多時候執行的程式都沒有改變,但卻常出現隨時間執行越久程式所耗用的空間將越多,最後造成out of memory。工程師也不知為何如此,就是定期在out of memory之前restart程式即可。這中現象層出不窮,一般大多是因為工程師沒有正確將記憶體回收所導致。Heap中的資料如果沒有正常的回收,將會逐步成長到將記憶體消耗殆盡,下次發生上述問題的實後,切記自己檢查一下heap空間的資料有無正常回收。論述到此有些讀者可能會覺得納悶:為何在寫Java都不需要注意回收空間的問題?~答案是因為Java中會採用Garbage Collection(垃圾回收)的機制自動檢查Heap中哪些資料已經沒有被使用,當確認資料已經沒有使用會自動將空間回收,如此工程師就專注撰寫程式即可,不用擔心記憶體回收不當等問題。

The conclusion is…當產生stack overflow一般是因為過多的函式呼叫(例如:遞迴太深)、或區域變數使用太多,此時請試著將stack size調大一點,另外檢查看看函式的呼叫跟變數的使用量。反之,當發生heap overflow請檢查是否都有正確將heap space的資料回收,另外採行的動態配置是否合理,不要過渡濫用而new出無謂的空間,若真的是程式過於複雜造成,請將heap size調大一些。


另一個參考點,整理得很不錯
http://alonchang.pixnet.net/blog/post/41170300-heap-%E5%92%8C-stack

二、<Heap>和<Stack>的理論知識
2.1申請方式
stack:
由系統自動分配。 例如,聲明在函數中一個局部變數 int b; 系統自動在<Stack>中為b開闢空間
heap:
需要programmer自己申請,並指明大小,在c中malloc函數
如p1 = (char *)malloc(10);
在C++中用new運算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在<Stack>中的。
2.2
申請後系統的回應
<Stack>:只要<Stack>的剩餘空間大於所申請空間,系統將為程式提供記憶體,否則將報異常提示<Stack>溢出。
<Heap>:首先應該知道作業系統有一個記錄空閒記憶體位址的link-list,當系統收到程式的申請時,
會 遍曆該link-list,尋找第一個空間大於所申請空間的<Heap>結點,然後將該結點從空閒結點link-list中刪除,並將該結點 的空間分配給程式,另外,對於大多數系統,會在這塊記憶體空間中的首位址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本記憶體空 間。另外,由於找到的<Heap>結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒link-list中。
2.3申請大小的限制
<Stack>: 在Windows下,<Stack>是向低位址擴展的資料結構,是一塊連續的記憶體的區域。這句話的意思是<Stack>頂的位 址和<Stack>的最大容量是系統預先規定好的,在 WINDOWS下,<Stack>的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超 過<Stack>的剩餘空間時,將提示overflow。因此,能從<Stack>獲得的空間較小。
<Heap>:<Heap> 是向高位址擴展的資料結構,是不連續的記憶體區域。這是由於系統是用link-list來存儲的空閒記憶體位址的,自然是不連續的,而link-list 的遍曆方向是由低位元址向高位址。<Heap>的大小受限於電腦系統中有效的虛擬記憶體。由此可見,<Heap>獲得的空間比較 靈活,也比較大。
2.4申請效率的比較:
<Stack>由系統自動分配,速度較快。但programmer是無法控制的。
<Heap>是由new分配的記憶體,一般速度比較慢,而且容易產生記憶體碎片,不過用起來最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配記憶體,他不是在<Heap>,也不是在<Stack>是直接在process的位址空間中保留一快記憶體,雖然用起來最不方便。但是速度快,也最靈活
2.5<Heap>和<Stack>中的存儲內容
<Stack>: 在函數調用時,第一個進<Stack>的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的位址,然後是函數的各個參數,在大多 數的C編譯器中,參數是由右往左入<Stack>的,然後是函數中的局部變數。注意靜態變數是不入<Stack>的。
當本次函數調用結束後,局部變數先出<Stack>,然後是參數,最後<Stack>頂指標指向最開始存的位址,也就是主函數中的下一條指令,程式由該點繼續運行。
<Heap>:一般是在<Heap>的頭部用一個位元組存放<Heap>的大小。<Heap>中的具體內容有programmer安排。


stack view
Schematic view of the stack

2012年6月26日 星期二

delegate的定義



參考: 
http://blog.csdn.net/pinklpig/article/details/7093796

http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/CommunicateWithObjects.html#//apple_ref/doc/uid/TP40002974-CH7-SW18

delegate翻译成什么还是很重要的,(delegate很多翻译成代理,中文的代理和delegate要表达的意思,有差别。这么翻译,只会增加学习者的难度)。
delegator:授权人
delegate:执行授权


A more realistic sequence involving a delegate
在Objective-c 中,不同对象间通信貌似只能通过protocol & delegate 实现。


使用 Delegate 作通信用途的 5 Steps

1. Create the @protocol
2. Add delegate @property to delegator’s public @interface
3. Use delegate property inside delegator’s implementation
4. Set the delegate property somewhere inside the delegate’s @implementation
5. Implement the protocol’s method(s) in the delegate (include <> on @interface)


sample code:
需要发送消息给其他类的类头文件中:
@protocol ShakeDelegate <nsobject>
@optional
//- (void)shakeAnimationStart;
- (void)callShakeAnimationStart;
- (void)callShakeAnimationStop;
@end

该类中添加变量:
id <shakedelegate> delegate;

M文件中发送信息:
[self.delegate callShakeAnimationStart];

在需要接受信息的类中:
@interface 添加继承
<ShakeDelegate>

设置需要传递的类的instance代理对象为自己:
childInstance.delegate = self;
在自己类实现delegate 方法:
- (void)callShakeAnimationStop{
// oops , i received the message from other class ....
}
完成。

class and instance method


Class Method

Starts with a plus sign
+ (id) alloc;
+ (Ship *)motherShip;
   + (NSString *)stringWithFormat:...
+(void) doSomething;

Creation & Utility Methods
Calling syntax
   [Class method]
   Ship *ship = [Ship motherShip];
   NSString *resultString = [NSString stringWithFormat:@“%g”, result];
   [[ship class] doSomething];// 呼叫方法



self/super is this class

self means “this class’s class methods”

super means “this class’s superclass’s class methods”


在使用上,self與super都是 class,因此呼叫的都是class的method
self只是一個pointer指向你自己。


甚麼時候使用class method

1. 創建 instance/object

2. share instance

3. get information from class



class是沒有類似instance的屬性及變數。


Instance method


Starts with a dash (-)
- (BOOL)dropBomb:(Bomb *)bomb
              at:(CGPoint)position
            from:(double)altitude;

“Normal” Instance Methods
Calling syntax
[<pointer to instance> method]
Ship *ship = ...; // instance of a Ship
destroyed = [ship dropBomb:firecracker
                               at:dropPoint
                                from:300.0];

self/super is calling instance
self means “my implementation”
super means “my superclass’s implementation”

[self greeting]; // 呼叫方法, 在同一檔案內, xcode的標準寫法

與 Class Method 的差別,在於
號,代表這是一個 Instance Method
其他則與 Class Method 相同。

另外,要使用 Instance Method必須先產生 Instance / Object (實體 / 物件)

實體呼應instance method
- (id) init;  // e.g. [[Hello alloc ] init ]  <---需要初始設定
- (void) greeting:(NSString *) word;

類別呼應class method
+ (id) alloc;   // e.g. [Hello alloc]
+ imageNamed:(UIImage) image;
// [UIImage imageNamed:@”hello.png”] 




Example 

image

image




@interface Vehicle  // Class  
- (void)move;
@end

@interface Ship : Vehicle  // class  inherit
- (void)shoot;
@end

Ship *s = [[Ship alloc] init];
[s shoot];
[s move];

2012年6月25日 星期一

The Dynamism of Objective-C

參考http://blog.csdn.net/ibright/article/details/6862226

Objective-C有3个动态特性


1,动态类型
Dynamic typing—determining the class of an object at runtime
运行时决定对象类型

2,动态绑定
Dynamic binding—determining the method to invoke at runtime
运行时决定方法调用

3,动态加载
Dynamic loading—adding new modules to a program at runtime
运行时加载新模块

(isa 指針) and (id) in Dynamic typing

蘋果原始資料
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html

isa 指針: NSObject 中有一個 Class isa 的指針類型的成員變量,因為我們的對象大都直接或者間接的從 NSObject 繼承而來,因此都會繼承這個 isa 成員變量,isa 在運行時會指向對象的 Class 對象, 一個類的所有對象的 Class 對象都是同一個(JAVA 也是如此),這保證了在內存中每一個類 型都有唯一的類型描述。這個 Class 對象中也有個 isa 指針,它指向了上一級的父類的 Class 對象。 在明白了這個 isa 之後,你就可以明白在繼承的時候,A extends B,你調用 A 的方法 a(),首 先 A 的 isa 到 A 的 Class 對象中去查找 a()方法,找到了就調用,如果沒找到,就驅使 A 的 Class 對象中的 isa 到父類 B 的 Class 對象中去查找。

參考 http://www.guan8.net/Java/1164462.html

Objective-C一個特別的data type。id就是:
typedef struct objc_object {
Class isa;
} *id;
而Class本身就是個pointer:
typedef struct objc_class *Class;
所以isa稱為isa pointer。
        基本設計理念就是:不管任何型態的 Object 都是由 pointer 來指定,這也就是為什麼在 Objective-C 裡,任何 Object variable 的宣告都是 pointer (*),只有 primitive data type 以及 C struct 是例外。

至此,我們可定義一個id object如下:
id anObject;
     
          與下面的寫法同義
       #import "MyObject.h"
          MyObject *anObject;
  
不同之處在於若寫成 MyObject *anObject; 時,compiler 能夠從 MyObject.h 得知 MyObject class 的宣告內容,而在 compile 時幫忙檢查對於 myobj 的存取是否符合定義。

 

nil 即為null object,也就是id值為0,id、nil及其他basic type object都在objc/objc.h裡面。
objects均是 dynamically typing,也就是說,在程式執行時(run time)才最後決定該object的type。
 Dynamic typing 也就是直到 Runtime 時才來決定 Object 究竟為何種 class,最重要的就   是 (id) 的設計

任何 Object 不論其類別為何,在 Runtime 時才會 allocate memory 並由 isa 來決定它真正的類別,而非如同 C++ 在 compile time 時,就安排好不同類別的記憶體配置。
這種不指定特定類別的方式其實就替"未來"可能有新的類別保留了非常大的彈性,也不需要特別以 design pattern 來花太多心思設計 abstract class (interface),對於寫程式的人來說可以很直覺。

PS. 這種 Dynamic typing 與 ECMAScript 中的 prototype chain 設計原理相同,但 ECMAScript 則有更大的彈性,可以在 Runtime 時任意改變其 prototype;雖然理論上 Objective-C 也可以辦得到,但目前似乎沒有這樣的設計。


 參考  http://愛瘋手機.tw/node/4664-2009-08-11.htm
           http://rintarou.dyndns.org/2010/12/09/objective-c-%E6%B7%BA%E8%AB%87/



Introspection


參考:http://psvsps2.blogspot.tw/2009/07/cocoa-fundamental-iphone-part2_31.html

動態型別(Dynamically type)和靜態型別(Statically Type)的優劣爭論持續了好一陣子, 動態型別程式語言帶來的靈活性,靜態型別的嚴謹各有千秋,動態型別表現傑出,幾個重要的程式語言如 python , ruby 都有相當亮眼的表現,Objective-C 也是一種動態型別的程式語言,通常動態型別程式語言會提供比較多的自省(introspection)能力,如 runtime 檢查type,檢查method等等。

 Objective-C’s runtime support allows you to discover various properties of objects at
execution time. This process is called introspection. You can find out an object’s class and
superclass using the methods class and superclass, as follows:

Class objectsClass;
Class objectsSuperClass;
id anObject;
objectsClass = [anObject class];
objectsSuperClass = [anObject superclass];

蘋果原始資料
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html

Introspection refers to the inherent ability of an object to divulge, upon request, its essential characteristics at runtime. By sending objects certain messages, you can ask them questions about themselves as objects and the Objective-C runtime provides you with answers. Introspection is an important coding tool because it makes your programs more efficient and robust.

因為所有的class都繼承自NSObject,因此有三個方便來辨認現在的狀態
All objects that inherit from NSObject know these methods
isKindOfClass: returns whether an object is that kind of class (inheritance included)
isMemberOfClass: returns whether an object is that kind of class (no inheritance)
respondsToSelector: returns whether an object responds to a given method

例如
You get a Class by sending the class method class to a class :)
if ([obj isKindOfClass:[NSString class]]) {
    NSString *s = [(NSString *)obj stringByAppendingString:@”xyzzy”];
}


Types of Introspection Information

The NSObject protocol, which is adopted by the NSObject class, defines introspection methods that yield the following kinds of information about an object:
  • Class membership. To determine if an object inherits, directly or indirectly, from a particular class, send it an isKindOfClass: message and evaluate the result. This method tells you if the object is a direct instance of the given class. You can also use the class and superclass methods to obtain the class or superclass of an object and then use that result in comparison operations.
  • Messages responded to. To find out if an object’s class or superclass implements a method, send the object a respondsToSelector: message. The parameter is a SEL-typed value constructed from the signature of the method using the @selector directive. For example:
    BOOL doesRespond = [anObject respondsToSelector:@selector(writeToFile:atomically:)];
  • Protocol conformance. If a class conforms to a formal protocol, you can expect it to implement the required methods of that protocol and send messages to it accordingly. Use the conformsToProtocol: method to obtain this information. You specify the argument of this method using the @protocol directive.



2012年5月29日 星期二

Archive and Serialization

轉貼自

1. http://rintarou.dyndns.org/tag/objective-c/ 
2. developer.apple.com/library

3. 完整的例子可以參考http://blog.skp.idv.tw/kun/

Archive 與 Serialization 是為了將 Hierarchical data 與 byte stream 相互轉換(encode/decode)而設計的兩種機制。

Encode : Hierarchical data -> byte stream
Decode : byte stream -> Hierarchical data

Archives (Un-arhchive)
Archive 能處理包含 Object 本身,以及與其它 Object 之間的 Relationships (references),保存原來完整 Object graph 的資訊並轉換成 byte stream,例如:nib。
要支援 Archive 機制,就必須實作 NSCoding Protocol,在 Fundation 裡的一些 Value objects(NSString, NSArray, NSNumber 等)都有實作 NSCoding Protocol。

Mac OS X archives store an arbitrarily complex object graph. The archive preserves the identity of every object in the graph and all the relationships it has with all the other objects in the graph. When unarchived, the rebuilt object graph should, with few exceptions, be an exact copy of the original object graph.
Interface Builder uses archives (nib file) to store the objects and relationships that make up a user interface. A Cocoa application loads the nib archive to reconstruct a window, menu, or view that was designed in Interface Builder.
Your application can use an archive as the storage medium of your data model. Instead of designing (and maintaining) a special file format for your data, you can leverage Cocoa’s archiving infrastructure and store the objects directly into an archive. With minimal effort, you can implement Save and Open in your application.
To support archiving, an object must implement the NSCoding protocol, which consists of two methods. One method encodes the object’s important instance variables into the archive and the other decodes and restores the instance variables from the archive.
All of the Foundation value objects (NSString, NSArray, NSNumber, and so on) and most of the Application Kit user interface objects implement NSCoding and can be put into an archive. Each class’s reference document identifies whether they implement NSCoding.

Serializations
Mac OS X serializations store a simple hierarchy of value objects, such as dictionaries, arrays, strings, and binary data. The serialization only preserves the values of the objects and their position in the hierarchy. Multiple references to the same value object might result in multiple objects when deserialized. The mutability of the objects is not maintained.
Property lists are examples of serializations. Application attributes (the Info.plist file) and user preferences are stored as property lists.
Arbitrary objects cannot be serialized. Only instances of NSArray, NSDictionary, NSString, NSDate, NSNumber, and NSData (and some of their subclasses) can be serialized. The contents of array and dictionary objects must also contain only objects of these few classes.



Class hierarchy for coders




















2012年5月27日 星期日

Xcode 4.2改版記錄

轉貼自 http://patty0800.pixnet.net/blog/post/38681516-xcode-4.2%E6%94%B9%E7%89%88%E8%A8%98%E9%8C%84part1_main,-button-setfont,-cfurlref

main.m 繼承的改變:
原來:
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePoolalloc] init];
int retVal = UIApplicationMain(argc, argv, nil, @"SampleAppDelegate");
[pool release];
return retVal;
}
新版:
int main(int argc, char *argv[])
{
    @autoreleasepool {
        returnUIApplicationMain(argc, argv, nil, NSStringFromClass([AnimButtonFlipAppDelegateclass]));
    }
}

/***********************************************************************/

UIButton文字大小設定:
原來:
 [button setFont:[UIFont boldSystemFontOfSize:24.0f]];
新版:
 [button.titleLabel setFont: [UIFont boldSystemFontOfSize24.0f]];

/**********************************************************************/

Core Foundation URL Access Utilities Reference:
原來:
CFURLRef baseURL = (CFURLRef)[[NSURL alloc] initFileURLWithPath:sndpath];
新版:
CFURLRef baseURL = (__bridge CFURLRef)[[NSURL alloc] initFileURLWithPath:sndpath];

Copy and mutableCopy

refer to  Addison Wesley - Programming.in.ObjectiveC.2.0.2nd (2009) 

int main (int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray    *dataArray = [NSMutableArray arrayWithObjects:
@ ” one ” , @ ” two ” , @ ” three ” , @ ” four ” , nil];
NSMutableArray    *dataArray2;

// simple assignment
dataArray2 = dataArray;
[dataArray2 removeObjectAtIndex: 0]; //移除第一筆資料,看對dataArray的影響
NSLog (@ ” dataArray: “ );
for ( NSString *elem in dataArray )
NSLog (@ ” %@ ” , elem);
NSLog (@ ” dataArray2: “ );
for ( NSString *elem in dataArray2 )
NSLog (@ ” %@ ” , elem);

// try a Copy, then remove the first element from the copy
dataArray2 = [dataArray mutableCopy]; //產生兩個不同的記憶區塊
[dataArray2 removeObjectAtIndex: 0]; //移除第一筆資料,看對dataArray的影響
NSLog (@ ” dataArray: “ );
for ( NSString *elem in dataArray )
NSLog (@ ” %@ ” , elem); 
NSLog (@ ” dataArray2: “ );
for ( NSString *elem in dataArray2 )
NSLog (@ ” %@ ” , elem);

[dataArray2 release];  //只需對dataArray2做release動作就可以了
[pool drain];
return 0;
}

dataArray:
two
three
four
dataArray2:
two
three
four

dataArray:
two     //資料不受影響,因為dataArray區已經與dataArray2區不同了
three
four
dataArray2:
three
four

Another Example for  mutable strings

int main (int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray    *dataArray = [NSMutableArray arrayWithObjects:
[NSMutableString stringWithString: @ ” one ” ], //裡面也是NSMutableString
[NSMutableString stringWithString: @ ” two ” ],
[NSMutableString stringWithString: @ ” three ” ],
nil
];
NSMutableArray    *dataArray2;
NSMutableString   *mStr;

NSLog (@ ” dataArray: “ );
for ( NSString *elem in dataArray )
NSLog (@ ” %@ ” , elem);

// make a copy, then change one of the strings
dataArray2 = [dataArray mutableCopy]; //  要產生兩個記憶區塊,但只針對dataArray裡的point參考區,有作複製的動作,對次一級的array資料區並沒有複製 
//因此dataArray及dataArray2雖有兩個不同point區的記憶區塊,但其兩邊的point只是指向相同的資料記憶區塊

mStr = [dataArray objectAtIndex: 0]; //針對array[0]將入"ONE"
[mStr appendString: @ ” ONE ” ];

NSLog (@ ” dataArray: “ );
for ( NSString *elem in dataArray )
NSLog (@ ” %@ ” , elem);

NSLog (@ ” dataArray2: “ );
for ( NSString *elem in dataArray2 )
NSLog (@ ” %@ ” , elem);

[dataArray2 release];
[pool drain];
return 0;
}

dataArray:
one
two
three

dataArray:
oneONE
two
three

dataArray2:
oneONE
two
three

以上所做的都只是shallow Copy,要將整個array內部含括所有Point指向的區塊的所有資料都備份,則需要Deep Copy 

Shallow and deep copies of an object 

 

Making a shallow copy
NSArray *shallowCopyArray=[someArray copyWithZone:nil];
 
NSDictionary *shallowCopyDict=[[NSDictionary alloc] initWithDictionary: someDictionary copyItems: NO];

Making a deep copy
NSArray *deepCopyArray=[[NSArray alloc] initWithArray: someArray copyItems: YES];
  

另一個真正的Deep Copy,使用壓縮解壓縮的方式, NSCoding protocol.

NSData *buffer;

buffer = [NSKeyedArchiver archivedDataWithRootObject: myArray1];
myArray2 = [NSKeyedUnarchiver unarchiveObjectWithData: buffer];