项目中的坑
指针
指针问题
例如:int * p 代表这个指针指向的类型是int;
例如:int numbers[4] = {10,20,30,40};
打印:NSLog(@"%p",numbers);打印结果:0x7fff5fbff810。是这个数组的首地址
打印:NSLog(@"%p",&numbers[0]);打印结果:0x7fff5fbff810。也是这个数组的首地址
打印:
for (NSInteger i = 0; i< 4; i++) {
NSLog(@"&numbers[%zd] == %p",i,&numbers[i]);
}
结果:
2016-05-25 11:59:19.295 JX-指针[2139:86165] &numbers[0] == 0x7fff5fbff810
2016-05-25 11:59:19.295 JX-指针[2139:86165] &numbers[1] == 0x7fff5fbff814
2016-05-25 11:59:19.295 JX-指针[2139:86165] &numbers[2] == 0x7fff5fbff818
2016-05-25 11:59:19.295 JX-指针[2139:86165] &numbers[3] == 0x7fff5fbff81c
地址每个地址之间相差4,是类型占用的字节数
打印:int *p;
p = &numbers[0];
NSLog(@"%p,%p",p,p+1);
结果:0x7fff5fbff810,0x7fff5fbff814
结论:指针 + 1 会根据指针所指向的类型来自动判断地址
打印:NSLog(@"%p -- %p",numbers,numbers + 1);
结果:0x7fff5fbff810 -- 0x7fff5fbff814
结论:数组名也是相当于数组元素的首地址指针,当期+1之后的结果也跟其类型有关
打印:NSLog(@"%p -- %p",numbers,numbers + 1);
NSLog(@"%p -- %p",&numbers,&numbers + 1);
结果:0x7fff5fbff810 -- 0x7fff5fbff814 // 跨度为4
0x7fff5fbff810 -- 0x7fff5fbff820 // 跨度为16
int nmbers[4] = {10,20,30,40};
int *p = (int *)(&numbers +1):
*(p - 1);
&numbers指的是整个数组,
+ 1 就是跨度为整个数组,指向了数组最后一位的后一位,超出数组范围
(int *)就是将其强转成int类型,赋值给指针p
之后指针p - 1 :因为其指针类型已经是int,所以就向后跨度一个类型字节,就是指向了40
指针 P + N : 代表P中存储的地址 + N * P所指向的类型实际占用的字节数
指针 P - N : 代表P中存储的地址 - N * P所指向的类型实际占用的字节数
P = &numbers[0]:代表指针P指向的是数组中10所在的地址
数组名:代表数组地址,也是数组元素的首地址;也相当与指向数组元素的指针
numbers:代表&numbers[0],也等价于指针numbers[0]的指针
&numbers:等价于指向numbers的指针,所以跨度就是整个指针, + 1 就是代表整个数组所占的空间的字节
UICollectionViewController中的cell点击不能执行代理方法
其中可能的原因就是在其上添加了tap点击手势,拦截了代理方法
小项目总结
微博动画
类似微博启动动画
- 自己封装一个动态控件,因为只是一个固定的布局,使用xib。
- 在使用xib创建好类,继承自UIView,关联
- 关联好之后先写一个类方法来加载xib
- 在控件添加到控制器上之后来设置动画
// 这个方法是当添加到父控件上时候调用
- (void)didMoveToSuperview
#import "JXWelcome.h"
@interface JXWelcome ()
@property (weak, nonatomic) IBOutlet UIImageView *shareImage;
@property (weak, nonatomic) IBOutlet UIImageView *iconImage;
@property (weak, nonatomic) IBOutlet UILabel *welcomeLabel;
@end
@implementation JXWelcome
+ (instancetype)welcome {
return [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
}
// 当将要加载到父视图上的时候
- (void)didMoveToSuperview {
// 设置头像属性
self.iconImage.layer.cornerRadius = self.iconImage.bounds.size.width / 2;
self.iconImage.clipsToBounds = YES;
self.iconImage.transform = CGAffineTransformMakeTranslation(0, 100);
// 添加微博标志动画,
[UIView animateKeyframesWithDuration:1 delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
// 隐藏微博问候语
self.shareImage.alpha = 0;
} completion:^(BOOL finished) {
self.iconImage.hidden = NO;
// 设置头像动画
[UIView animateWithDuration:1 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:0 options:UIViewAnimationOptionCurveLinear animations:^{
self.iconImage.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished) {
self.welcomeLabel.alpha = 0;
self.welcomeLabel.hidden = NO;
// 设置欢迎文字
[UIView animateWithDuration:1 animations:^{
self.welcomeLabel.alpha = 1;
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
}];
}];
}
@end
导航栏
// 如果要设置背景图片,必须填UIBarMetricsDefault,默认导航控制器的子控制器的view尺寸会变化。
// 设置导航条背景图片,一定要在导航条显示之前设置
// 直接在子控制器上的viewDidLoad这个方法中使用的话,因为控制器的view都是懒加载,所以在使用的时候,设置导航栏背景是无用的
获取当前所有的导航栏,这里可以一次性设置所有的导航栏
// 但是设置这个属性的时候回改变系统的导航栏,例如调用相册的时候,真机调试的时候会有bug
UINavigationBar * bar = [UINavigationBar appearance];
[bar setBackgroundImage:[UIImage imageNamed:@"NavBar64"] forBarMetrics:UIBarMetricsDefault];
但是这个方法会一次性设置全部的导航栏,包括我们系统的默认的导航栏
// 获取哪个类,在ios9之后我们可以使用这个来设置我们自定义的类的导航栏
UINavigationBar * bar = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[self class]]];
[bar setBackgroundImage:[UIImage imageNamed:@"NavBar64"] forBarMetrics:UIBarMetricsDefault];
// iOS9之前的方法
UINavigationBar * bar = [UINavigationBar appearanceWhenContainedIn:self,nil];
[bar setBackgroundImage:[UIImage imageNamed:@"NavBar64"] forBarMetrics:UIBarMetricsDefault];
// 当前类或者他的子类第一次使用的时候才会调用,而且只会调用一次
+ (void)initialize {
// 获取当前所有的导航栏
// 设置导航栏属性,不需要考虑是否存在导航条,只需要执行一次
// 但是设置这个属性的时候回改变系统的导航栏,例如调用相册的时候,真机调试的时候会有bug
// UINavigationBar * bar = [UINavigationBar appearance];
// [bar setBackgroundImage:[UIImage imageNamed:@"NavBar64"] forBarMetrics:UIBarMetricsDefault];
// 获取哪个类
UINavigationBar * bar = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[self class]]];
[bar setBackgroundImage:[UIImage imageNamed:@"NavBar64"] forBarMetrics:UIBarMetricsDefault];
// 设置导航条文字颜色
[bar setTintColor:[UIColor whiteColor]];
// 设置导航栏标题颜色
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
dict[NSForegroundColorAttributeName] = [UIColor whiteColor];
dict[NSFontAttributeName] = [UIFont boldSystemFontOfSize:18];
[bar setTitleTextAttributes:dict];
}
调用方法
// 当前类或者他的子类第一次使用的时候才会调用,而且只会调用一次
+ (void)initialize {}
@property在类扩展中使用的话,只会生成set,get方法,不会生成_成员属性,以及方法的实现、
self.view.frame这个frame就是在类别中使用
类方法中不能访问成员属性,需要使用类.属性来访问。
// 在.h文件中
#import "JXMenuView.h"
#import "JXMenuModel.h"
#define kCols 3
@interface JXMenuView ()
/** 测试属性 */
@property (nonatomic,strong) NSArray * array;
@end
@implementation JXMenuView
+ (void)show {
JXMenuView * menu = [[self alloc] init];
menu.array;// 这样子来调用访问属性
}
设置导航栏背景
// 设置导航栏背景颜色,必须在导航栏还没有显示的时候设置,如果自定义导航栏,在其中设置了背景颜色,那么这里设置就会失败
// 图片尺寸不够需要拉伸
UIImage * image = [UIImage imageNamed:@"NLArenaNavBar64"];
image = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5];
[self.navigationController.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];
重写,自定义控制器view
// 重写,自定义控制器view
- (void)loadView {
UIImageView * imageView = [[UIImageView alloc] initWithFrame:JXBouns];
imageView.image = [UIImage imageNamed:@"NLArenaBackground"];
// 打开交互
imageView.userInteractionEnabled = YES;
self.view = imageView;
}
当UITabViewController中的单元格是固定的,我们可以用静态单元格,静态单元格的设置方法
加载的时候使用方法,这里不需要绑定类
// 发现
// 采用storyBoard设置
UIStoryboard * storyBoard = [UIStoryboard storyboardWithName:@"JXDiscoverViewController" bundle:nil];
JXDiscoverViewController * discover = [storyBoard instantiateInitialViewController];
自定义UIButton,定义图片在文字右边
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat titleX = self.titleLabel.width;
CGFloat imageX = self.imageView.x;
if (self.imageView.x < self.titleLabel.x) { // 当图片在文字左边的时候调用
self.titleLabel.x = imageX;
self.imageView.x = titleX;
}
}
当更改UIButton中内容的时候,我们需要设置[self sizeToFit];为自适应。我们可以重写设置方法,来调用的时候自动刷新
- (void)setTitle:(NSString *)title forState:(UIControlState)state {
[super setTitle:title forState:state];
// 自适应,自动计算宽度高度
[self sizeToFit];
}
获取segue线
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIViewController * vc = segue.destinationViewController;// 目的控制器
UIViewController * vc = segue.sourceViewController; // 源控制器
vc.hidesBottomBarWhenPushed = YES;
}
获取版本号码
// 获取info.plist文件中
[NSBundle mainBundle].infoDictionary
启动效果
启动效果,启动检测有更新,会显示引导图,引导图上动画是向左滑动的时候图片从右向左进入,向右滑动的时候图片从右向左进入
CGFloat offsetX = scrollView.contentOffset.x;
CGFloat distance = offsetX - self.oldOffsetX;
// 先将位置移动到下一个位置
self.guideLargetView.x += distance * 2;
self.guideSmallView.x += distance * 2;
self.guideView.x += distance * 2;
[UIView animateWithDuration:0.5 animations:^{
self.guideView.x -= distance;
self.guideSmallView.x -= distance;
self.guideLargetView.x -= distance;
}];
int page = offsetX / JXWidth + 1;
// 修改控件的内容
self.guideView.image = [UIImage imageNamed:[NSString stringWithFormat:@"guide%d",page]];
self.oldOffsetX = offsetX;
当push的时候隐藏栏
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { // 当导航控制器push的时候回调用这个方法。
if (self.viewControllers.count != 0) { // 第一次的时候还没走到super这个方法,所以self.viewControllers.count还是为0,当不为0的时候就隐藏
viewController.hidesBottomBarWhenPushed = YES;
}
[super pushViewController:viewController animated:animated];
}
自定义导航控制器
// 当前类或者他的子类第一次使用的时候才会调用,而且只会调用一次
+ (void)initialize {
// 获取当前所有的导航栏
// 设置导航栏属性,不需要考虑是否存在导航条,只需要执行一次
// 但是设置这个属性的时候回改变系统的导航栏,例如调用相册的时候,真机调试的时候会有bug
// UINavigationBar * bar = [UINavigationBar appearance];
// [bar setBackgroundImage:[UIImage imageNamed:@"NavBar64"] forBarMetrics:UIBarMetricsDefault];
// 获取哪个类
UINavigationBar * bar = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[self class]]];
[bar setBackgroundImage:[UIImage imageNamed:@"NavBar64"] forBarMetrics:UIBarMetricsDefault];
// 设置导航栏标题颜色
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
dict[NSForegroundColorAttributeName] = [UIColor whiteColor];
dict[NSFontAttributeName] = [UIFont boldSystemFontOfSize:18];
[bar setTitleTextAttributes:dict];
// 设置导航返回图片
// 当不是跟控制器的时候设置返回按钮
UIImage * image = [UIImage imageWithRenderingOriginalImage:@"NavBack"];
UIBarButtonItem * bar = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStylePlain target:self action:@selector(back:)];
viewController.navigationItem.leftBarButtonItem = bar;
}
设置返回按钮
[bar setTintColor:[UIColor whiteColor]];
[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -100) forBarMetrics:UIBarMetricsDefault];