提示:由于水平有限,如发现有疑问或错误的地方请毫不客气的提出、讨论,我会在第一时间回复,感谢在先
0.注意APi可使用范围
重要的事情说三遍 注意API 可使用范围
重要的事情说三遍 注意API 可使用范围
1.块的反向使用
已知 :aVC,aVC.searchBar ; bVC,bVC.block
aVC addChildVC:bVC
searchBar代理方法:
searchBarBeginSearch{ bVC.block(); };
2.AVAudioPlayer
播放界面和player控制逻辑分开.
初始化方法中路径转换成百分比的形式
parse 和stop都是停止播放.但是有区别的
(void)pause; / pauses playback, but remains ready to play. /
(void)stop; / stops playback. no longer ready to play. /
NSString* songPath = [[NSBundle mainBundle]pathForResource:self.songs.firstObject ofType:@"mp3"];
//C函数把songPath进行URL转换.(资源含有中文会报错)
songPath = StePercentEscapedStringFromString(songPath);
NSURL* songUrl = [NSURL URLWithString:songPath];
NSError* error;
self.player = [[AVAudioPlayer alloc]initWithContentsOfURL:songUrl error:&error];
if (error) {
NSLog(@"error:%@",error.localizedDescription);
return;
}
if (self.player) {
//初始化后,prepareToPlay前,如果如果需要调整播放速率,需要打开enableRate开关
//To enable adjustable playback rate for an audio player, set this property to YES after you initialize the player and before you call the prepareToPlay instance method for the player.
self.player.enableRate = YES;
self.player.numberOfLoops = 0;
[self.player prepareToPlay];
}
3.ViewController.h文件中的属性无法赋值.
从XIB中拉出的组件,如果在创建的时候用这种方式:VC.label.text = @"XX";有可能赋值失败;原因:执行 VC.label.text = @"XXX"时候,label还没有从Xib中创建好; 可以调用此方法强制加载控件:
-(void)loadViewIfNeeded NS_AVAILABLE_IOS(9_0); // Loads the view controller's view if it has not already been set.
也可以给VC添加另外的属性,作为中间间使用,在ViewDidLoad中给IBOut组件赋值.
由于初始化时书写顺序有问题,造成VC属性无法赋值
UIViewController *vc = [[UIViewController alloc] init];
//在这里配置View可能过早导致ViewDidLoad方法执行;然而在ViewDidLoad 中使用userModel时为空;(把View的配置写在最后就可以了)
vc.view.frame = self.view.bounds;
UserModel* model = [UserModel new];
model.account = @"account";
vc.model = model;
[self addChildViewController:vc];
[self.view addSubview:vc.view];
4.判断系统版本
4.1宏定义
#define SystemVersion [[[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."][0] intValue] //只是提取主版本号
4.2使用NSFoundationVersionNumber来判断
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_9_x_Max){
NSLog(@"systemVersion >=10.0.0");
}
4.3使用UIProcessInfo
//对NSOperatingSystemVersion进行封装,使用的时候写在头文件即可
NSOperatingSystemVersion SteOperationMake(NSInteger majorVersion,NSInteger minorVersion,NSInteger patchVersion){
NSOperatingSystemVersion systemVersion ={majorVersion,minorVersion,patchVersion};
return systemVersion;
}
//使用NSProcessInfo类可以获取关于当前进程的信息.这里主要获取关于系统版本的信息。
NSProcessInfo* info = [NSProcessInfo processInfo];
/*
typedef struct {
NSInteger majorVersion;(主版本)
NSInteger minorVersion;(次版本)
NSInteger patchVersion;(修订版本)
} NSOperatingSystemVersion;
NSOperatingSystemVersion 是结构体类型.
*/
NSLog(@"%ld %ld %ld", info.operatingSystemVersion.majorVersion,info.operatingSystemVersion.minorVersion,info.operatingSystemVersion.patchVersion); //10 2 0 基于当前手机的测试数据
NSLog(@"%@", info.operatingSystemVersionString); //Version 10.2 (Build 14C92) 基于当前手机的测试数据
NSOperatingSystemVersion systemVersion;
systemVersion.majorVersion = {9,0,0};
//这里也可以使用上面封装的SteOperationMake(9, 0, 0);
//Returns a Boolean value indicating whether the version of the operating system on which the process is executing is the same or later than the given version.
NSLog(@"%d",[info isOperatingSystemAtLeastVersion:systemVersion]); //当前版本是否大于等于9.0
4.4 也可以使用 someClass.class 或者 respondsToSelector 进行判断
//使用respondsToSelector有一定风险:比如有一个方法在低版本中是私有方法.
//在高的系统版本中这个方法又被公开了,这中情况下是有被拒的危险的
//@property (readonly, copy) NSString *localizedUppercaseString NS_AVAILABLE(10_11, 9_0);
if ([@"" respondsToSelector:@selector(localizedUppercaseString)]){
NSLog(@"判断是否响应某个方法!");
}
//UIStackView: NS_CLASS_AVAILABLE_IOS(9_0)
if ([UIStackView class]) {
NSLog(@"可以创建StackView");
}
//建议使用这种方法
if (NSClassFromString(@"UIStackView")) {
NSLog(@"可以创建StackView");
}
//对于与硬件相关类可以使用类提供的询问方法进行测试
比如:UIImagePickerController
+ (BOOL)isSourceTypeAvailable:(UIImagePickerControllerSourceType)sourceType;
//枚举值
typedef NS_ENUM(NSInteger, UIImagePickerControllerSourceType) {
UIImagePickerControllerSourceTypePhotoLibrary,
UIImagePickerControllerSourceTypeCamera,
UIImagePickerControllerSourceTypeSavedPhotosAlbum
}
5.SCrollView相关概念
5.1 contentOffset:The point at which the origin of the content view is offset from the origin of the scroll view
5.2 contentSize:The size of the content view(可视内容)
5.3 contentInsert:The distance that the content view is inset from the enclosing scroll view
e.g.:
scrollView frame = (0 20; 320 548) contentSize: {320, 600}
//设置contentInset会触发scrollViewDidScroll方法执行 偏移量为(0,-70)
self.scrollView.contentInset = UIEdgeInsetsMake(70, 0, 70, 0);
//手指在0-70范围内移动时候,scrollView是可以移动的
//scrollView停止滑动时候偏移量:-70,600-548+70
//立即contentOffSet 与 contentInset 区别
5.4 -canCancelContentTouches(method): A Boolean value that controls whether touches in the content view always lead to tracking(一个用来控制ContentView的触摸事件,是否总是被追踪的布尔值)
Discuss: If the value of this property is YES and a view in the content has begun tracking a finger touching it, and if the user drags the finger enough to initiate a scroll, the view receives a touchesCancelled:withEvent: message and the scroll view handles the touch as a scroll. If the value of this property is NO, the scroll view does not scroll regardless of finger movement once the content view starts tracking.(翻译:如果布尔值为YES,并且ContentView手指的触摸事件已经被追踪,用户拖动ContentView足够长触发ScrollView开始滑动,ContentView会收到touchesCancelled:withEvent: 消息,与此同时scrollView把触摸视为滑动;如果属性值为NO,scrollView是不会滑动的,当content开始追踪就忽略手指的移动,简而言之:如果属性为NO,scrollVie不会滚动)
5.5 delaysContentTouches: If the value of this property is YES, the scroll view delays handling the touch-down gesture until it can determine if scrolling is the intent. If the value is NO , the scroll view immediately calls touchesShouldBegin:withEvent:inContentView:. The default value is YES.
5.6工作原理:
Because a scroll view has no scroll bars, it must know whether a touch signals an intent to scroll versus an intent to track a subview in the content. To make this determination, it temporarily intercepts a touch-down event by starting a timer and, before the timer fires, seeing if the touching finger makes any movement. If the timer fires without a significant change in position, the scroll view sends tracking events to the touched subview of the content view. If the user then drags their finger far enough before the timer elapses, the scroll view cancels any tracking in the subview and performs the scrolling itself. Subclasses can override the touchesShouldBegin:withEvent:inContentView:, pagingEnabled, and touchesShouldCancelInContentView: methods (which are called by the scroll view) to affect how the scroll view handles scrolling gestures.
参考内容链接:http://www.cnblogs.com/wayne2... 以及官方文档5.7 scrollView在快速拖拽的时候会contentOffSet数值会发生跳变:scrollView采用定时器采样scrollView偏移量.
6 定时器
6.1 定时器会停止计数,当scrollView滑动的时候,解决方法加入把定时器 添加到runLoop 的commandModel.
6.2 定时器造成循环引用,这个在高效52个方放中有讲.不过多解释
6.3 ( 特定场景 )eg:订单列表中如果是支付中的订单;有一个倒计时5分钟而后取消订单的需求;与此同时后台也有一个5分钟倒计时取消的操作;针对这种情况最好在5分钟倒计时结束的时候去从新拉取数据(后台在倒计时结束会自动取消订单)从而避免移动端操作的麻烦.(最好不要去在移动端定时器结束后去调取消订单的操作:支付完成后如果没有返回app这时候的定时器还在运行就会取消订单)
7.edgesForExtendedLayout
设置重叠部分该如何显示.
Prior to(在iOS7之前) iOS 7, the UIViewController.View did not visually underlap(重叠) parent elements such as the status bar, navigation bar, or toolbar. In iOS 7, it typically should.
The UIViewController.EdgesForExtendedLayout specifies to the UIViewController.ParentViewController how the edges of this UIViewController should be extended for underlap. The default value of UIRectEdge.All specifies that all edges should be extended to underlap(子控制器视图的边界到延伸到与父控制器视图重叠的部分), while UIRectEdge.None specifies an extent similar to that in iOS 6 or earlier.
UIRectEdge.All :重叠部分延伸; UIRectEdge.None:重叠部分不延伸
摘选:https://developer.xamarin.com...7.2 automaticallyAdjustsScrollViewInsets:
The default value of this property is YES, which lets container view controllers know that they should adjust the scroll view insets of this view controller’s view to account for screen areas consumed by a status bar, search bar, navigation bar, toolbar, or tab bar. Set this property to NO if your view controller implementation manages its own scroll view inset adjustments.(主要解决当scrollView被状态栏、导航栏遮挡的情况下自动调整contentInsert)
7.3 extendedLayoutIncludesOpaqueBars:布局是否包括透明的Bars
8.应用授权范例
ALAuthorizationStatus alStatus = [ALAssetsLibrary authorizationStatus] ;
if (alStatus == ALAuthorizationStatusDenied ||alStatus == ALAuthorizationStatusRestricted) {
UIAlertAction* confirmAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
//跳转到设置界面进行授权.
//NSURL* settingUrl = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
//iOS10 iOS8 也是可以正常运行.
NSURL* settingUrl = [NSURL URLWithString:@"App-prefs:root=Privacy&path=Photos"];
//UIApplicationOpenSettingsURLString NS_AVAILABLE_IOS(8_0);(使用这个 选项进行设置也是可以的,建议使用然后弹出一个HowToDo界面)
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_9_x_Max) {
if ([[UIApplication sharedApplication] canOpenURL:settingUrl]) {
[[UIApplication sharedApplication] openURL: settingUrl options:@{} completionHandler:^(BOOL success) {
NSLog(@"跳转成功!");
}];
}
}else{
if ([[UIApplication sharedApplication] canOpenURL:settingUrl]) {
[[UIApplication sharedApplication] openURL:settingUrl];
}
}
}];
UIAlertAction* cancleAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
UIAlertController* alterVC = [UIAlertController alertControllerWithTitle:@"想访问您的相册" message:nil preferredStyle:UIAlertControllerStyleAlert];
[alterVC addAction:confirmAction];
[alterVC addAction:cancleAction];
[self presentViewController:alterVC animated:YES completion:nil];
}else{
///已经授权
[self continueAccessAlbum];
}
9.UIPickerView 大小
UIPickerView大小在ios9.之前是很难改变的,之后就可以了
UIPickerView and UIDatePicker are now resizable and adaptive—previously, these views would enforce a default size even if you attempted to resize them. These views also now default to a width of 320 points on all devices, instead of to the device width on iPhone.
Interfaces that rely on the old enforcement of the default size will likely look wrong when compiled for iOS 9. Any problems encountered can be resolved by fully constraining or sizing picker views to the desired size instead of relying on implicit behavior.
参考链接:https://developer.apple.com/l...
10.UICollectionView.collectionViewLayout 内容.
collectionViewLayout property of UICollectionView is of type UICollectionViewLayout. You can assign any custom subclass of type UICollectionViewLayout to collectionView instance Similarly apple has created a subclass called UICollectionViewFlowLayout which inherits from UICollectionViewLayout Because its a subclass of UICollectionViewLayout you can set UICollectionViewFlowLayout instance to collectionView.collectionViewLayout property and UICollectionViewFlowLayout class has a property named minimumLineSpacing and obviously its parent class which is UICollectionViewLayout does not have it ) In your case u created a instance of parent class (UICollectionViewLayout) and tried accessing the property defined in child class (UICollectionViewFlowLayout). Obviously compiler could not find that property hence crashed(有一点需要注意collectionView实例默认的collectionViewLayout类型是UIcollectionViewFlowlayout)