项目中遇到的问题

哇咔咔,终于开始了自己的项目,嘿嘿,现在把做项目过程中遇到的问题和一些技巧记下来。

—————————–

appicon问题

一开始遇到了appicon的问题,唉,连@2x和@3x都不知道是啥意思。然后往上面放图片的时候就一直报错。

这里写图片描述
就是上面这个,首先要知道@2x就是扩大2倍,@3x就是扩大3倍。然后扩大谁的倍数呢,就是下面那个40pt,所以你在相应位置放图标时要保证大小跟要求的一样,还有就是命名方式,在图片名称后面加上其放大倍数,比如”imageName@2x”。嗯,就是酱紫。

然后遇到了pch的问题,我用的是Xcode7,自从Xcode6开始苹果就不在新建项目的时候自动创建.pch文件了。于是乎,我就自己创建呗,然后我笨笨的,连这一步也出现了问题,自己翻的时候愣是没看见,其实就在iOS->other里面的PCH文件。

这里写图片描述

然后创建完了,我就写预定义的一些东西。然后嘞,发现并不能用。。。我就搜一搜,这是咋的了。因为我得设置一些东西

这里写图片描述

把Precompile Prefix Header右边的NO改为Yes,然后在Precompile Prefix Header下边的Prefix Header右边双击,添加刚刚创建的pch文件的工程路径,添加格式:“$(SRCROOT)/项目名称/pch文件名” ,$(SRCROOT)的意思就是工程根目录的意思,后面那个pch文件名要加上.pch后缀。

然后就可以使用在pch中预定义的东西了。

—————————–

精简代码问题

下面说说精简代码的问题。一般当我们写一段代码发现重复性太多的时候,就要考虑一下重构了。就是把变化的地方变成参数,不变的地方抽到一个函数中。

—————————–

tabbar图片位置问题

虽然遇到问题的时候烦恼的不行,但是,解决的就有新的收获,超开心哈哈,虽然,现在还什么都没做出来呢。

在设置tabbarItem的图片的时候遇到了一些问题。

iOS7之后image出现了新的功能,就是渲染图片,暂时这样说。有下面三种枚举类型,效果如下图。

UIImageRenderingModeAutomatic,  
UIImageRenderingModeAlwaysOriginal,     
UIImageRenderingModeAlwaysTemplate

这里写图片描述

这个就看你自己想要的效果了,我想要original那种的,就是按我自己配的图来,不用你渲染。

这个我又遇到了一个小问题,就是我发现我选择的时候是按我设置好的选择的图片来的,但是,不选择的时候被渲染成灰色的了。。。这是怎么回事,我百思不得姐啊。后来,我才发现,我太马虎了,一个是默认的图片,另一个是选中图片,我只向选中图片发送imageWithRenderingMode:消息了,默认的忘记发送了,怪不得错了,活该。。

接着再运行还有问题,就是整个图片向上飘,就是下面这个样子

这里写图片描述

设置一下inset属性就可以,如下操作:

UIEdgeInsets insets = UIEdgeInsetsMake(6, 0, -6, 0);//至于为什么是6我还不太清楚,先放着
childVc.tabBarItem.imageInsets = insets;

然后这块就暂时没有问题了,哈哈。

—————————–

隐藏tabbar问题

在用tabbarcontroller时,在其中一个界面点击跳转到另一个界面时,会发现底下的tabbar还在,这可能不是我们想要的效果,不过没关系,设置一下就好。
当你要跳转到另一个视图控制器的时候,你肯定要创建一个对吧,然后设置他的hidesBottomBarWhenPushed属性为YES就可以了。

即酱紫:

UIViewcontroller *vc = [[UIViewcontroller alloc] init];
vc.hidesBottomBarWhenPushed = YES;

搞定。

—————————–

控件显示问题

当你发现一个控件显示不出来的时候,有可能时内容有问题,或者是忘记设置尺寸了。尤其是自定义的东西,一定要设置尺寸。
还有一点需要注意就是不能给控件的size赋值,因为UIView(控件都是继承自UIView),要么就在初始化的时候吧size设置好,要不就设置frame。所以这样会造成一些不必要的麻烦,这个时候category就有用处了,为UIView写一个分类,添加上相应的属性,然后完成setter和getter方法就可以了。

举个例子:

- (void)setY:(CGFloat)y {
    CGRect frame = self.frame;
    frame.origin.y = y;
    self.frame = frame;
}

—————————–

定制按钮

因为想要定制导航控制器上的导航按钮,所以自定义一个导航控制器,然后重写pushViewController: animated:这个方法,即拦截该方法,记得要在里面调用一下父类的这个方法。然后就可以做一些我想要的操作了,比如我想定制它的导航按钮,然后我蠢蠢的去设置navigationController的navigationItem属性(即self.navigationItem)。对于这个行为我有一下感想。

我又犯蠢了,犯蠢了,蠢死了。对于navigationController的navigationItem属性是只读的!亲!睁大眼睛看清楚,看属性的时候把参数也看清楚了好吗!!!

嗯,所以在这个方法里面这样设置就可以了viewController.navigationItem.leftBarButtonItem。
这个也涉及到经验问题,有的人一下就发现,我们一般不都是在viewController里面设置这个属性吗。嗯,经验很重要。

然后你可以在注意一点,就是你可能定制的是返回按钮,如果这样的话,第一次push的界面并不需要放上返回箭头。所以你可以在上面的方法里面判断一下。

self.viewControllers.count > 1 // 如果该导航控制器里面的自控制器大于1的时候才需要返回上一个界面,这里也要注意,这个判断应该放在调用父类的该方法下面,至于为什么,自己思考一下

后期,如果你某个子控制器不想用这个定制的item,那么你可以进行覆盖。怎么覆盖呢,首先我们要知道它是先执行push操作,然后再执行每个子控制器的viewDidLoad方法

—————————–

duplicate 编译错误

当编译遇到 duplicate symbol _OBJC_METACLASS…..错误时,一般情况下就是导入了.m 文件。
或者就是项目中有两个一样的.m文件。

—————————–

封装代码

当遇到一大段一大段重复的代码的时候,比如,你有很多导航控制器,你想要给它设置barbuttonItem,那么你就会写很多这样重复的代码,因为他还有left和right。这个时候就要想到封装,而且为了提高易读性,就用category进行封装,对哪个对象进行封装就给哪个对象添加分类和类方法,这就就是所谓工厂模式,把一个东西的创建封装起来,只调用接口就好了,不用管工厂中是如何创建的,这个时候就要好好考虑一下参数的设置问题。要注意命名格式,最好遵守[NSString stringwith…]这种格式。

—————————–

关于字体属性问题。

之前蠢蠢的以为如果要更改文字的颜色只能通过绘制的方法,蠢死了。新技能get。

UIBarButtonItem *item = [UIBarButtonItem appearance];
    // key : NS***AttributeName
NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
textAttrs[NSForegroundColorAttributeName] = XGJColor(253, 132, 171, 1.0);
textAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:16];
[item setTitleTextAttributes:textAttrs forState:UIControlStateNormal];

嗯,就酱紫就搞定了。

—————————–

调试技巧

开发中我们经常要打印日志,就会写很多NSLog。。。但是发布的时候要注释掉这些打印,否则会耗性能。难道要一个一个写一个一个主食。没那么傻,get新技能吧。
在pch文件中写入下面的代码就搞定了。

#ifdef DEBUG

#define XGJLog(...) NSLog(__VA_ARGS__) // 处于开发阶段
#else
#define XGJLog(...)  // 处于发布阶段
#endif

—————————–

关于SearchBar

在写这个SearchBar的时候,会有很多限制。比如你放进去一个图片,太大了,你想设置一个宽高,就设置不了。所以,用Textfield来写,怎么写呢,textfield长得不是就很像搜索框吗。然后他有一个leftview属性,设置leftview的同时也要设置一下leftViewMode,因为如果不设置他默认是UITextFieldViewModeNever,也就是永远不显示。

代码如下:

UITextField *searchBar = [[UITextField alloc] init];
searchBar.width = 520;
searchBar.height = 40;
searchBar.background = [UIImage imageNamed:@"searchbar_textfield_icon"];

UIImageView *searchIcon = [[UIImageView alloc] init];
searchIcon.image = [UIImage imageNamed:@"search_icon"];
searchIcon.width = 26;
searchIcon.height = 26;
searchIcon.contentMode = UIViewContentModeCenter; // 这里设置图片为居中效果
searchBar.leftView = searchIcon;
searchBar.leftViewMode = UITextFieldViewModeAlways;
self.navigationItem.titleView = searchBar;

关于那个textfield的图片,可以进行拉伸,这个选中图片后在工具栏中Attributes Inspector里面的最下面,有个Slicing,把SLice设置为Horizontal and Vertical ,然后Center 为Stretches就行了,其他属性他是自己自动设置的。这里的话,还不是很清楚这是为什么,但是如果你不这么操作,会很丑。因为我找不到那种宽度的搜索框,是由一个正方形进行拉伸的。

—————————–

创建ImageView的小细节

以下两个创建ImageView对象的方法是有区别的,注意一下。不仅仅是UIImageView,还有其他的控件也有这样的问题,因此要记住这个地方,以后出现问题知道是怎么回事。

UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; // 这种方法会将imageVIew的宽高设置为图片的宽高
UIImageView *imageView = [[UIImageView alloc] init]; // 这种方式创建完是没有宽高的,除非你屌用initWithFrame初始化他的宽高 

—————————–

转换坐标系原点

当把B加入A视图的时候,B的frame是以A为参照的。有的时候我们想让B参照C,那么调用下面的方法就可以转换一下坐标原点了。

CGRect newFrame = [view convertRect:view.bounds toView:anotherView]; // 将坐标系原点转换为anotherView的
CGRect newFrame = [view.superview convertRect:view.frame toView:anotherView ];

转换坐标系原点,就是该控件的x、y的值加上当前参照与转换后参照相差的值。

—————————–

重写父类方法

我常犯的一个错误,就是在重写父类的时候忘记调用父类的该方法,就导致很多东西和想象的不一样,大忌大忌。切记,一定要在重写父类方法时,再super一下!

—————————–

继承类的代理问题

当你继承的父类已经有delegate属性时,那么只要你这个类中的delegate要求遵守的协议遵守一下父类delegate属性中要求遵守的那个协议就好了。

Person.h
@property(nonatomic, weak) id< FatherDelegate > delegate;


Student.h

@protocol StudentDelegate< FatherDelegate >
// method
@end

@interface Student:Person
@property (nonatomic, weak) id< StudentDelegate > delegate;
@end

—————————–

控制器与视图

当控制器的View还在,但是View上没有该有的数据,很有可能是因为控制器被提前销毁了

—————————–

关于info.plist

系统自带的这个plist文件无法通过url来访问,需要通过bundle。

—————————–

版本新特性

关于版本新特性,可以通过读取现有版本与上一次访问的版本号进行对比,如果不同启动版本新特性,相同就正常启动应用。通过沙盒进行存取。

—————————–

切换控制器

切换控制器有三种常用方法

  • pushViewController (navigation)
  • modal (即从底部向上弹的效果)-presentViewController: animated: completion:
  • 利用window.rootViewController切换 (用这种方法切换可以使旧控制器销毁,不继续占用内存)

—————————–

获取ScrollView的子视图

ScrollView 不要用lastObject去取scrollView.subviews 里面的最后一个view,因为你并不能确定里面有多少个view,因为系统可能会在其中创建一些view。所以取到的很有可能不是你想要的,这样做很危险。

注意imageView默认是不能交互的,需要手动开启交互imageView.userInteractionEnabled = YES;

—————————–

面向对象而不是面向字典

在开发过程中可能需要存储一些信息,刚开始可能觉得放到一个字点钟就可以了,但是,这样会给以后的开发带来很多麻烦,比如你读取时都要手写字符串,你不可能全都记住,他又不会提示,而且还容易打错。就非常不方便。这种时候最好将字典转成模型。也就是新建一个类,然后用字典去初始化那个类,这样面向对象的开发。

—————————–

EdgeInsets

EdgeInsets的参数是像素哦。而且对于EdgeInsets这种方式来修改布局更适合那种固定宽高的文字和视图,如果要是文字经常改变就不适合这种方式。这个时候可以封装一个button,自己定义布局。比如继承UIButton 然后重写layoutSubviews。
对于retina屏幕,像素是对对实际尺寸放大两倍,即乘以一个[UIScreen mainScreen].scale

—————————–

关于父子控制器

有的时候我们会让一个视图成为另一个的子视图,这个时候一定要让他们的控制器也称为父子关系,不然那个子视图的控制器就会被提前销毁,导致无法显示数据。
[self addChildViewController:myselfInfoTVC];

—————————–

—————————–

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值