iOS开发经验总结2


整理了下这个几年的笔记,看到很多的知识点都是iOS7, iOS6,iOS5的,更新换代好快啊。仅仅来回味下常用到基础点,大神们请绕行。有不对的地方请大家指出,会及时修改。


一、调节UINavigationBar的leftBarButtonItem离左边的距离 (iOS11 不可用)
UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back-button-whiteArrow.png"] style:UIBarButtonItemStylePlain target:self action:@selector(logoutBarBtnPressed:)];

UIBarButtonItem *fixedBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];

fixedBarButtonItem.width = -15;

self.navigationItem.leftBarButtonItems = [NSArray arrayWithObjects:fixedBarButtonItem, buttonItem, nil];

距离左边很近很近

根据fixedButton.width配置离左边的距离。


二、RestKit 保存数据到core data

通过RestKit将数据保存到core data中,entity为

@interface Article : NSManagedObject

@property (nonatomic, retain) NSNumber* articleID;
@property (nonatomic, retain) NSString* title;
@property (nonatomic, retain) NSString* body;
@property (nonatomic, retain) NSDate* publicationDate;

@end

@implementation Article // We use @dynamic for the properties in Core Data
@dynamic articleID;
@dynamic title;
@dynamic body;
@dynamic publicationDate;

@end

设置object mapping

RKEntityMapping* articleMapping = [RKEntityMapping mappingForEntityForName:@"Article"
                                                      inManagedObjectStore:managedObjectStore];
[articleMapping addAttributeMappingsFromDictionary:@{
                                                     @"id": @"articleID",
                                                     @"title": @"title",
                                                     @"body": @"body",
                                                     @"publication_date": @"publicationDate"
                                                     }];

articleMapping.identificationAttributes = @[ @"articleID" ];

其中的identificationAttributes 设置的数组中的值,就是用来判断返回的数据是更新还是new。


三、RestKit 添加relationship

Author Entity

@interface Author : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *email;

@end

Article Entity

@interface Article : NSObject

@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *body;
@property (nonatomic) Author *author;
@property (nonatomic) NSDate *publicationDate;

@end

添加好关系friendship

// Create our new Author mapping
RKObjectMapping* authorMapping = [RKObjectMapping mappingForClass:[Author class] ];

// NOTE: When your source and destination key paths are symmetrical, you can use addAttributesFromArray: as a shortcut instead of addAttributesFromDictionary:

[authorMapping addAttributeMappingsFromArray:@[ @"name", @"email" ]];

// Now configure the Article mapping
RKObjectMapping* articleMapping = [RKObjectMapping mappingForClass:[Article class] ];
[articleMapping addAttributeMappingsFromDictionary:@{
                                                     @"title": @"title",
                                                     @"body": @"body",
                                                     @"publication_date": @"publicationDate"
                                                     }];

// Define the relationship mapping
[articleMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"author"
                                                                               toKeyPath:@"author"
                                                                             withMapping:authorMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:articleMapping
                                                                                        method:RKRequestMethodAny
                                                                                   pathPattern:nil keyPath:@"articles"
                                                                                   statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

在Json转Model的时候,使用JTObjectMapping方法很类似。减少很多的工作量。


四、xcode找不到设备

原因:
Deployment Target版本比真机版本高,导致找不到。将Deployment Target设置成与真机的系统版本一致。


五、autolayout 自动布局

autoLayout 需要在- (void)viewDidLoad 方法执行完后生效,所以需要在- (void)viewDidAppear:(BOOL)animated 方法中再进行frame的获取,此时才能取到正确的frame。


六、Navigation backBarButtonItem 设置

**根据苹果官方指出:backbarbuttonItem不能定义customview,所以,只能贴图或者,让leftBarButtonItem变成自定义返回按钮,自己写个方法进行[self.navigationController pop当前Item **

之前大家是否疑惑为什么设置了类似这样的代码

UIBarButtonItem *backButton = [[UIBarButtonItem alloc]
                               initWithTitle:@"返回"
                               style:UIBarButtonItemStylePlain
                               target:self
                               action:nil];

self.navigationItem.backBarButtonItem = backButton;

界面上backButton并没出现“返回”的字样.

其实是被leftBarButtonItem和rightBarButtonItem的设置方法所迷惑了leftBarButtonItem和rightBarButtonItem设置的是本级页面上的BarButtonItem,而backBarButtonItem设置的是下一级页面上的BarButtonItem.
比如:两个ViewController,主A和子B,我们想在A上显示“刷新”的右BarButton,B上的BackButton显示为“撤退”就应该在A的viewDidLoad类似方法中写:

UIBarButtonItem *refreshButton = [[UIBarButtonItem alloc]
                                  initWithTitle:@"刷新"
                                  style:UIBarButtonItemStylePlain
                                  target:self
                                  action:nil];

self.navigationItem.rightBarButtonItem = refreshButton;

UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
                                 initWithTitle:@"撤退"
                                 style:UIBarButtonItemStylePlain
                                 target:self
                                 action:nil];

self.navigationItem.backBarButtonItem = cancelButton;

而B不需要做任何处理然后ApushB就可以了.


七、AFNetworking 使用ssl
sharedClient.securityPolicy.allowInvalidCertificates = YES;

八、NSJSONSerialization 使用数据类型要求

进行JSON转化的时候,需要满足一下的要求。

An object that may be converted to JSON must have the following properties:

  • The top level object is an NSArray or NSDictionary.
  • All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
  • All dictionary keys are instances of NSString.
  • Numbers are not NaN or infinity.

也就是说:nil,基础数据不能转化为JSON。


九、NSArray进行不定参数处理
+ (NSArray *)arrayWithObjectsExceptionNil:(id)firstObj, ...
{
    NSMutableArray *tempMArray = [[NSMutableArray alloc] initWithCapacity:5];
    id eachObject = nil;
    va_list argumentList;
    
    if ( firstObj ) {
        [tempMArray addObject:firstObj];
        va_start(argumentList, firstObj);
        
        while ( (eachObject = va_arg(argumentList, id))){
            if ( nil != eachObject ){
                [tempMArray addObject:eachObject];
            }
        }
        
        va_end(argumentList);
    }
    
    return nil;
}

十、获取version
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
    
    // app名称
    NSString *app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];
    // app版本
    NSString *app_Version = [infoDictionary objectForKey:@"CFBundleShortVersionString"];
    // app build版本
    NSString *app_build = [infoDictionary objectForKey:@"CFBundleVersion"];

**注意:appid,在申请提交的时候,在itunesconnect的这个里面生成了,审核通过了也不会改变。
**


十一、no input file 错误

如果在编译的时候找不到文件,需要先在Build Phases中的Compile Sources 将不存在的文件删除,然后再将找不到的文件添加到project中。


十二、cg,cf,ca,ui等开头类

你还可以看到其他名字打头的一些类,比如CF、CA、CG、UI等等,比如
CFStringTokenizer 这是个分词的东东
CALayer 这表示Core Animation的层
CGPoint 这表示一个点
UIImage 这表示iPhone里面的图片

CF说的是Core Foundation,CA说的是Core Animation,CG说的是Core Graphics,UI说的是iPhone的User Interface


十三、file's owner 含义

file's owner 就是xib对应的类,如view对应的xib文件的file's owner对应的类就是viewcontroller的类。
file’s owner 是view和viewcontroller之间的对应关系的桥梁。(即,一个视图,如何知道自己的界面的操作应该由谁来响应)


十四、iOS coin 不透明

一般iOS app coin应该是不透明的,并且不可以在app中多次使用app coin。


十五、判断自定义类是否重复

自定义类库中,需要重写NSObject的两个固定方法来判断类是否重复:

- (BOOL)isEqual:(id)anObject;
- (NSUInteger)hash;

十六、IOS常用宏
// Macro wrapper for NSLog only if debug mode has been enabled
#ifdef DEBUG
#define DLog(fmt,...) NSLog(fmt, ##__VA_ARGS__);
#else
// If debug mode hasn't been enabled, don't do anything when the macro is called
#define DLog(...)
#endif

#define MR_ENABLE_ACTIVE_RECORD_LOGGING 0

#define IS_OS_6_OR_LATER    ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0)
#define IS_OS_7_OR_LATER    ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
#define OBJISNULL(o) (o == nil || [o isKindOfClass:[NSNull class]] || ([o isKindOfClass:[NSString class]] && [o length] == 0))
#define APP ((AppDelegate*)[[UIApplication sharedApplication] delegate])
#define UserDefaults                        [NSUserDefaults standardUserDefaults]
#define SharedApplication                   [UIApplication sharedApplication]
#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
#define RGB(r, g, b)                        [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0]
#define RGBA(r, g, b, a)                    [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]

十七、判断是否是4寸屏
#define iPhone5 ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 1136), [[UIScreen mainScreen] currentMode].size) : NO)

十八、NSString格式限定符
说明符 描述
%@ Objective-c 对象
%zd NSInteger
%lx CFIndex
%tu NSUInteger
%i int
%u unsigned int
%hi short
%hu unsigned short
%% %符号

十九、声明变量 在ARC下自动初始化为nil

NSString *s;

非ARC
的情况下, s指向任意地址,可能是系统地址,导致崩溃。

ARC
的情况下,s已经自动初始化为nil。


二十、向NSArray,NSDictionary等容器添加元素需判nil

[_paths addObject:[_path copy]];

如果这个_path为nil,那么就会出现一个crash。因为在容器中不能存放nil,可以用[NSNull null]来保存.

推荐 pod 'XTSafeCollection', '~> 1.0.4' 第三方库,对数组的越界,赋值nil,都有保护作用。


二十一、ceil命令 floor命令

Math中一个算法命令。
函数名: ceil用 法: double ceil(double x);功 能: 返回大于或者等于指定表达式的最小整数头文件:math.h

float f = 1.2222;
NSLog(@"f is %f.", ceil(f));

打印: f is 2.000000.

函数名: floor功 能: 返回小于或者等于指定表达式的最大整数用 法: double floor(double x);头文件:math.h

float f = 1.2222;
NSLog(@"f is %f.", floor(f));

打印: f is 1.000000.


二十二、Xcode中对某个类进行非ARC的设置

在Xcode点击工程,在工程中选择“TARGETS”你的工程,在Build Phases中选择“Compile Sources”,找到你需要设置非ARC的类,在这个类的右边有一个“Compiler Flags”,在这个里面设置“-fno-objc-arc
”。
那么这个类就是非ARC进行编译了。


二十三、storyboard上不能进行scrollview滚动

storyboard上不能进行scrollview滚动的原因是: autolayout引起的


二十四、延长APP的启动时间
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [NSThread sleepForTimeInterval:3.0f];

    return YES;

}

二十五、xcode调试的时候不运行watchdog

在利用Xcode进行调试时,watchdog不会运行,所在设备中测试程序启动性能时,不要将设备连接到Xcode。


二十六、语言国际化 NSLocalizedString

如果你使用的是Localizable.strings,那么你在程序中可以这样获取字符串:
NSLocalizedString(@"mykey", nil)

如果你使用的是自定义名字的.strings,比如MyApp.strings,那么你在程序中可以这样获取字符串:

NSLocalizedStringFromTable (@"mykey",@"MyApp", nil)

这样即可获取到"myvalue"这个字符串,可以是任何语言。


二十七、UIAppearance 使用

使用UIAppearance进行外观的自定义。

[+ appearance]修改整个程序中某个class的外观

[[UINavigationBar appearance] setTintColor:myColor];

[+ appearanceWhenContainedIn:]
当某个class被包含在另外一个class内时,才修改外观。

 [[UILabel appearanceWhenContainedIn:[cusSearchBar class], nil] setTextColor:[UIColor redColor]];

二十八、将NSString转换成UTF8编码的NSString

在使用网络地址时,一般要先将url进行encode成UTF8格式的编码,否则在使用时可能报告网址不存在的错误,这时就需要进行转换
下面就是转换函数:

NSString *urlString= [NSString stringWithFormat:@"http://www.baidu.com"];
NSString *encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes( kCFAllocatorDefault, (CFStringRef)urlString, NULL, NULL,  kCFStringEncodingUTF8 ));
NSURL *url = [NSURL URLWithString:encodedString];

或者使用下面的方法:

NSString *utf8Str = @"Testing";
NSString *unicodeStr = [NSString stringWithCString:[utf8Str UTF8String] encoding:NSUnicodeStringEncoding];

有时候获取的url中的中文等字符是乱码,网页内容是乱码,需要进行一下转码才能正确识别NSString,可以用下面的方法:

//解决乱码问题()

NSString *transString = [NSString stringWithString:[string stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

二十九、NSDateFormatter设定日期格式 AM
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setAMSymbol:@"AM"];
[dateFormatter setPMSymbol:@"PM"];
[dateFormatter setDateFormat:@"dd/MM/yyyy hh:mmaaa"];
NSDate *date = [NSDate date];
    
NSString *s = [dateFormatter stringFromDate:date];

显示效果为:
10/05/2010 03:49PM


三十、判断NSString为纯数字
//判断是否为整形:

- (BOOL)isPureInt:(NSString*)string{
    NSScanner* scan = [NSScanner scannerWithString:string];
    int val;
    return[scan scanInt:&val] && [scan isAtEnd];
}

//判断是否为浮点形:

- (BOOL)isPureFloat:(NSString*)string{
    NSScanner* scan = [NSScanner scannerWithString:string];
    float val;
    return[scan scanFloat:&val] && [scan isAtEnd];
}

if( ![self isPureInt:insertValue.text] || ![self isPureFloat:insertValue.text])
{
    resultLabel.textColor = [UIColor redColor];
    
    resultLabel.text = @"警告:含非法字符,请输入纯数字!";
    
    return;
}

三十一、image的正确使用

iOS中从程序bundle中加载UIImage一般有两种方法。
第一种比较常见:imageNamed
第二种方法很少使用:imageWithContentsOfFile

为什么有两种方法完成同样的事情呢?imageNamed的优点在于可以缓存已经加载的图片。苹果的文档中有如下说法:
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.

这种方法会在系统缓存中根据指定的名字寻找图片,如果找到了就返回。如果没有在缓存中找到图片,该方法会从指定的文件中加载图片数据,并将其缓存起来,然后再把结果返回。

imageWithContentsOfFile方法只是简单的加载图片,并不会将图片缓存起来。这两个方法的使用方法如下:

UIImage *img = [UIImage imageNamed:@"myImage"]; // caching  
// or  
UIImage *img = [UIImage imageWithContentsOfFile:@"myImage"]; // no caching 

那么该如何选择呢?

如果加载一张很大的图片,并且只使用一次,那么就不需要缓存这个图片。这种情况imageWithContentsOfFile比较合适——系统不会浪费内存来缓存图片。

然而,如果在程序中经常需要重用的图片,那么最好是选择imageNamed方法。这种方法可以节省出每次都从磁盘加载图片的时间。


三十二、将图片中间部分放大

根据图片上下左右4边的像素进行自动扩充。

UIImage *image = [UIImage imageNamed:@"png-0016"];
UIImage *newImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(50, 50, 50, 50) resizingMode:UIImageResizingModeStretch];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 50, 200, 400)];
imageView.image = newImage;
imageView.contentMode = UIViewContentModeScaleAspectFill;

使用方法- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode NS_AVAILABLE_IOS(6_0); // the interior is resized according to the resizingMode
进行对图片的拉伸,可以使用UIImageResizingModeTile和UIImageResizingModeStretch两种拉伸方式。
**注意:
**此方法返回一个新的UIImage,需要使用这个新的image。

注:UIEdgeInsets设置的值不要上下或左右交叉,不然会出现中间为空白的情况。

在Xcode5中也可以使用新特性 Slicing,直接对图片进行设置,不需要在代码中设置了。


三十三、UIImage和NSData的转换
NSData *imageData = [NSData dataWithContentsOfFile:imagePath];
UIImage *aimage = [UIImage imageWithData:imageData];
//UIImage 转化为 NSData
NSData *imageData = UIImagePNGRepresentation(aimage);

三十四、NSDictionary和NSData转换
// NSDictionary -> NSData:
NSData *myData = [NSKeyedArchiver archivedDataWithRootObject:myDictionary];
    
// NSData -> NSDictionary:
NSDictionary *myDictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:myData];

三十五、NSNumberFormatter 价格采用货币模式

如果显示的数值为价格,则用货币模式

NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
self.introView.guaranteedDataLabel.text = [formatter stringFromNumber:self.quoteEntity.guranteedInfo.guaranteedPrice];

三十六、画虚线的方法
CGFloat lengths[] = {5, 5};

CGContextRef content = UIGraphicsGetCurrentContext();

CGContextBeginPath(content);

CGContextSetLineWidth(content, LINE_WIDTH);

CGContextSetStrokeColorWithColor(content, [UIColor blackColor].CGColor);

CGContextSetLineDash(content, 0, lengths, 2);

CGContextMoveToPoint(content, 0, rect.size.height - LINE_WIDTH);

CGContextAddLineToPoint(content, rect.size.width, rect.size.height - LINE_WIDTH);

CGContextStrokePath(content);

CGContextClosePath(content);

三十七、设备转屏
- (BOOL)shouldAutorotate
{
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeLeft;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeLeft;
}

在storyboard中设置只支持竖屏,可以在单个UIViewController中加入这3个方法,使得这个UIViewController只支持左横屏。


三十八、UITextField 弹出UIDatePicker

设置UITextField的inputView可以不弹出键盘,而弹出UIDatePicker。

首先需要在View加载结束的时候指定文本的InputView

UIDatePicker *datePicker = [[UIDatePicker alloc] init];  
datePicker.datePickerMode = UIDatePickerModeDate;  
[datePicker addTarget:self action:@selector(dateChanged:) forControlEvents:UIControlEventValueChanged];  
self.txtDate.inputView = datePicker;  

然后需要指定当UIDatePicker变动的时候的事件是什么. 此处就是为了给文本框赋值.

- (IBAction)dateChanged:(id)sender  
{  
    UIDatePicker *picker = (UIDatePicker *)sender;  
    self.txtDate.text = [NSString stringWithFormat:@"%@", picker.date];
   
}  

然后当文本框编辑结束时, 需要让UIDatePicker消失.

- (IBAction)doneEditing:(id)sender  
{  
    [self.txtDate resignFirstResponder];  
}  

然后把文本框在IB中, 指向定义好的txtDate就行了~


三十九、将Status Bar字体设置为白色
  1. 在Info.plist中设置UIViewControllerBasedStatusBarAppearance为NO

  2. 在需要改变状态栏颜色的ViewController中在ViewDidLoad方法中增加:

UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

如果需要在全部View中都变色,可以写在父类的相关方法中。


四十、UILongPressGestureRecognizer执行2次的问题
//会调用2次,开始时和结束时
- (void)hello:(UILongPressGestureRecognizer *)longPress
{
    if (longPress.state == UIGestureRecognizerStateEnded)//需要添加一个判断
    {
        NSLog(@"long");
        
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"hello"
                              
                                                        message:@"Long Press"
                              
                                                       delegate:self
                              
                                              cancelButtonTitle:@"OK"
                              
                                              otherButtonTitles:nil, nil];
        
        [alert show];
    }
}


四十一、View中事件一次响应一个
self.scrollView.exclusiveTouch = YES;

设置exclusiveTouch这个属性为YES。


四十二、UIScrollView中立即响应操作

delaysContentTouches 属性是UIScrollView中立即响应Touch事件。默认是YES,如果想点击后马上有反应,则将该值设置为NO。


四十三、UITableView在Cell上添加自定义view

如果在UITableView上添加一个自定义的UIView,需要注意在view中的颜色会因为Cell被选中的点击色,而引起view的颜色变化,并且不可逆。


四十四、NSNotificationCenter 注销

当 NSNotificationCenter 注册一个通知后

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullableNSString *)aName object:(nullableid)anObject;

在class的dealloc中,一定要使用

- (void)removeObserver:(id)observer name:(nullable NSString *)aName object:(nullable id)anObject;

进行注销。

不能用 - (void)removeObserver:(id)observer;进行通知的注销。

注意: 如果不注销,将导致class不会被释放。


四十五、H5开发的弊端

H5开发的弊端: 占用内容太多。在打开H5的时候,会占用大量的内存,在项目中看到,一般会达到一个页面50M的内存。


四十六、interactivepopgesturerecognizer 使用

设置left bar button后,会导致右滑返回的效果失效,查看完美的设置方案。

同时为了获取到右滑返回的事件,可以执行

[self.navigationController.interactivePopGestureRecognizer addTarget:self action:@selector(back)];

**在ViewController中viewDidAppare中添加,在viewWillDisappear中remove。
**


四十六、masonry 中使用两个UIView之间设置layout
[self.bottomOpenStoreBtn mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(promptImageView.mas_bottom).with.offset(30);
        make.height.mas_equalTo(44);
        make.width.mas_equalTo(SCREEN_WIDTH - 30);
        make.centerX.mas_equalTo(self.promptScrollView);
        make.bottom.mas_equalTo(self.promptScrollView.mas_bottom).with.offset(-30);
    }];

设置self.bottomOpenStoreBtn的顶部与promptImageView的顶部距离30pt
make.bottom.mas_equalTo(self.promptScrollView.mas_bottom).with.offset(-30);
其中的 self.promptScrollView.mas_bottom 必须使用mas_bottom,不能使用bottom.

make.top 中的top为
- (MASConstraint*)top

self.promptScrollView.bottom 中的bottom为

- (float) bottom
{    return CGRectGetMaxY (self.frame);
}

即一个是layout属性,另一个为frame的属性。


推荐阅读更多精彩内容