您的位置:首页 > 移动开发 > IOS开发

IOS学习之斯坦福大学IOS开发课程笔记(第四课)

2014-05-08 10:20 821 查看
转载请注明出处

作者:小马

第三节课没什么重要内容,直接跳过。



这节课前半节课, 其实是对第二课的深入,第二课讲了一个简易的计算器,这节课让这个计算器“可编程”。所谓的“可编程”就是可以解析变量并计算,比如我传入”3+2”,就可以得到结果5。 老师在课堂上只实现了部分功能,完整的是作为学生的作业。下半节课讲关于view的一些概念。





一 上半节课



1 增加两个类方法作为公共的API, 为了向上兼容,上节课的那两个也还保留。如下:

@interface calculatorBrain : NSObject
 
- (void)pushOperand:(double)operand;
- (double)performOperation:(NSString *)operation;
 
@property (nonatomic, readonly)id program;
+ (double)runProgram:(id)program;
+ (NSString*) descriptionOfProgram:(id)program;
 
@end


2 让内部的数据堆栈更加通用。

原来的堆栈只能存操作数,不能存操作符,这里要让它也能存操作符。如下(为了增加可读性,把它的名字也改了):

@interface calculatorBrain ()
@property (nonatomic, strong)NSMutableArray *programStack; //可以存操作数和操作符。
@end
 
-(void)pushOperand:(double)operand
{
    [self.programStack addObject:[NSNumber numberWithDouble:operand]];
}
-(double)performOperation:(NSString *)operation
{
    [self.programStack addObject:operation];//操作符也进栈
    return [calculatorBrain runProgram:self.programStack];
}


3 popOperand方法就用不到了:

//-(double)popOperand
//{
//   NSNumber *operandObject = [self.operandStack lastObject];
//   
//   //注意这里,如果operandObject为nil, 下面执行remove会让程序崩溃,所以要加上判断
//    //lastObject方法不用判断
//    if (operandObject)
//    {
//        [self.operandStack removeLastObject];
//    }
//   
//    return [operandObject doubleValue];
//}



4 为program实现getter.

Program是只读属性,只要实现getter就行了,我们打算用这个getter返回内部的programStack。 但是有个问题,programStack是内部的一个变量,我们不希望别人破坏它,所以只是返回它的一个copy,如下:

-(id)program
{
    return [self.program copy];
}


而且,对一个NSMutableArray做copy,得到的是一个NSArray。 是不可改变的。 如果想要得到可变的,要用mutableCopy。Stackoverflow上有如下的解释:



mutableCopy alwaysreturns a mutable result.
copy alwaysreturns an immutable result。


5 runProgram做了什么

代码如下:

+ (double)runProgram:(id)program
{
    NSMutableArray *stack;
    if ([program isKindOfClass:[NSArray class]])
    {
       //注意这个判断条件是不能少的,并不是id类型都有mutableCopy方法。
        stack = [program mutableCopy];
    }
    return [self popOperandOffStack:stack];
}
 
+ (double)popOperandOffStack:(NSMutableArray *)stack
{
    double result = 0;
   
    //注意类型是id, 因为取出来的可能是操作数,也可能是操作符。
    id topStack= [stack lastObject];
    if(topStack)
    {
        [stack removeLastObject];
    }
   
    if([topStack isKindOfClass:[NSNumber class]])
    {
        result = [topStack doubleValue];
    }
    else if([topStackisKindOfClass:[NSString class]])
    {
        NSString*operation = topStack;
       
        if([operation isEqualToString:@"+"]) //只实现加法
        {
            result = [self popOperandOffStack:stack] +[self popOperandOffStack:stack];
        }
       
    }
   
   
    return result;
}


源码下载地址:
http://download.csdn.net/detail/pony_maggie/7314481



二 下半节课



首先讲到创建一个view的方法示例,这里注意一下self.view的用法,self指的是当前的controller, self.view就是这个controller的top level view.





另外,要补充一点,这节课里老师不断的强调简单这个词,他的意思是,最好的代码一定是最少的的代码实现同样的功能。果然是apple出来的人,提倡简单之美.



接着,什么时候我们需要自定义一个view(custom view), 如何自定义一个view?





主要是两个情况,一是要重画view, 二是重定义touch事件.



重画的方法马上就说了,重载drawRect方法就可以了,给个实现的示例,注意这里实现调用的都是基于C的API, 回想一下第一节课讲IOS架构时的内容,融会贯通一下。

//绘制一个方块
-(void)drawRect:(CGRect)rect {  
    // Drawing code.  
    //获得处理的上下文    
    CGContextRef context =UIGraphicsGetCurrentContext();    
    //设置线条样式    
    CGContextSetLineCap(context, kCGLineCapSquare);    
    //设置线条粗细宽度    
    CGContextSetLineWidth(context,1.0);     
    
    //设置颜色    
   CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);     
    //开始一个起始路径    
    CGContextBeginPath(context);    
    //起始点设置为(0,0):注意这是上下文对应区域中的相对坐标,    
    CGContextMoveToPoint(context, 0,0);     
    //设置下一个坐标点    
    CGContextAddLineToPoint(context,100, 100);     
    //设置下一个坐标点    
    CGContextAddLineToPoint(context,0, 150);    
    //设置下一个坐标点    
    CGContextAddLineToPoint(context,50, 180);    
    //连接上面定义的坐标点    
    CGContextStrokePath(context); 
      
}




记得不要主动调用drawRect方法,它是系统调用的,你只要实现就行了。 当然你可以通知系统你改了drawRect,用下面两个方法:

setNeedsDisplay

setNeedsDisplayInRect



drawRect只会被调用一次, 因为draw是很expensive的(请原谅我装逼,卖弄英文),比如我自己定义了一个view, 这个view里面有一些属性,然后外部通过setter访问了这些属性, 那这个view的drawRect也只会被调用一次,并不是你调用一次setter,drawRect就调用一次.



如何在自定义视图上写文字?





有两种方式, 一种最直观的方法,用UILabel,生成一个UILabel的实例,设置它的text属性,非常简单。



另一种方式是自己”画文字”, 首先定义字体:

UIFont *myFont = [UIFontsystemFontOfSize:12.0];
UIFont *theFont = [UIFont fontWithName:@”Helvetica”size:36.0];




然后是NSString:

NSString *text = “abc”;
[text drawAtPoint:(CGPoint)pwithFont:theFont];


这个看起来有点奇怪,NSString是foundation kit里的对象,怎么能用来”画图”呢,关键在于drawAtPoint这个方法,这个方法通过category机制,加到UIKit里,所以它其实算是NSString在UI框架里的一个扩展.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐