AVPlayer 暂停继续播放
最近在开发一款视频直播的应用,其中有一个功能是进入后台暂停,再次进入前台后继续播放的问题,可以通过 Appdelegate 中处理这个问题,先上代码
- (void)applicationWillResignActive:(UIApplication *)application
{
[player pause];
pausedtime = player.currentTime
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[player seekToTime:pausedtime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
[player play];
}
思路是
在进入后台,即将不活跃的时候,记录下当前时间,就是上面代码的 pausedtime,这里需要在 Appdelegate 里面定义一下 float *pausedtime
在 applicationWillResignActive 中获取当前暂停的时间
在 applicationDidBecomeActive 中续播
MD5 加密
新建 NSObject,命名为 MD5
头文件 MD5.h
#import <Foundation/Foundation.h>
@interface MD5 : NSObject
+ (NSString*)md5:(NSString *)stringToEncrypt;
@end
主文件 MD5.m
#import "MD5.h"
#import <CommonCrypto/CommonDigest.h>
@implementation MD5
/*
* @param stringToEncrypt 需要被加密的字符串
* @return md5加密后的32位字符串,小写结尾用lowercaseString,大写用uppercaseString
*/
+ (NSString*)md5:(NSString *)stringToEncrypt
{
const char *cStr = [stringToEncrypt UTF8String];
unsigned char result[16];
CC_MD5(cStr, (CC_LONG)strlen(cStr), result );
return [[NSString stringWithFormat:
@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
] lowercaseString];
}
@end
使用方法
引入头部文件 MD5.h
需要加密处使用 [MD5 md5:待加密字符串]
其他信息
内容解释+ (NSString *)md5:(NSString *)stringToEncrypt
;方法 stringToEncrypt
待加密字符串 lowercaseString/uppercaseString
返回字符串为小写/大写
iOS 中关闭键盘
iOS 中经常需要用到关闭键盘,基本有三种方式
[self.view endEditing:YES]
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponser) to:nil from:nil forEvent:nil];
[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
至于如何触发这些事件,看自己实际需求解决。
iPhone 分辨率
想想有点醉,某一个从事了四年 iOS 开发的人,居然至今连各代 iPhone 的分辨率都不知道,他也算是可以了。
官方链接:Screenshot specifications
Mac 下的应用
Icon 16px - 1024px,翻倍式。
iOS 开发之字体自定义
一天客户对我说:“*哥,你给我们做的这个应用,我们觉得字体不好看,能换个我们想要的字体么?
”,同时递上了字体。
我说:“没问题!”,拿过新字体,开始工作。
重命名为 adai.ttf,直接拖入到项目资源中。
编辑 Info.plist
文件,添加 Fonts provided by application
,Item 的值就是刚才我重命名的字体名字 adai.ttf。
然后调用方法 + (UIFont *)fontWithName:(NSString *)fontName size:(CGFloat)fontSize;,如 _lbTitle.font = [UIFont fontWithName:@"adai" size:20];
但是却不能正常显示,原来有时候字体名字并不是我重命名后的名字,咋办?
- (void)listAllFonts {
NSArray *fontFamilies = [UIFont familyNames];
for (NSString *fontFamily in fontFamilies) {
NSArray *fontNames = [UIFont fontNamesForFamilyName:fontFamily];
NSLog (@"%@: %@", fontFamily, fontNames);
}
}
通过上面这段代码,列出字体名字,做了上面的修改,客户高兴的拿着修改字体后的应用回去了。
Swift 版本
查看字体
var i = 0
for family: String in UIFont.familyNames {
print("\(i)---font---\(family)")
for names: String in UIFont.fontNames(forFamilyName: family) {
print("== \(names)")
}
i += 1
}
使用字体
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
label.text = ""
let font = UIFont(name: "adai", size: 13)
if font != nil {
label.font = font
}
隔了两三天,客户又来找:“*哥,我觉得新字体好看,但我们老板想看看其他几个字体,你能帮我多放几个字体进去么?”
我说:“你们真的麻烦,给你们弄个字体下载的吧。”,说完开工。
添加库 CoreText.framework 并引入文件 #import <CoreText/CoreText.h>
- (void)downloadFont
{
NSString *URL_FONT = @"download_url/adai.otf";
NSString *fontName = @"adai";
NSData *dynamicFontData = [NSData dataWithContentsOfURL:[NSURL URLWithString:URL_FONT]];
if (!dynamicFontData)
return;
CFErrorRef error;
CGDataProviderRef providerRef = CGDataProviderCreateWithCFData((CFDataRef)dynamicFontData);
CGFontRef font = CGFontCreateWithDataProvider(providerRef);
if (! CTFontManagerRegisterGraphicsFont(font, &error))
{
CFStringRef errorDescription = CFErrorCopyDescription(error);
NSLog(@"Failed to load font: %@", errorDescription);
CFRelease(errorDescription);
}
else
self.dynamicFontLabel.font = [UIFont fontWithName:fontName size:50];
CFRelease(font);
CFRelease(providerRef);
}
每次访问都要下载字体,那得多浪费流量,所以,又做了下判断,如果已经下载的就直接使用,没有下载的那就下载。
- (BOOL)hasFont:(NSString *)fontName
{
UIFont* theFont = [UIFont fontWithName:fontName size:13.0];
BOOL downloaded = (theFont && ([theFont.fontName compare:fontName] == NSOrderedSame || [theFont.familyName compare:fontName] == NSOrderedSame));
return downloaded;
}
搞定,客户拿走了新应用。
ps. iOS 中自带的字体
0---项目字体---Devanagari Sangam MN
== DevanagariSangamMN
== DevanagariSangamMN-Bold
1---项目字体---Avenir Next
== AvenirNext-Medium
== AvenirNext-DemiBoldItalic
== AvenirNext-DemiBold
== AvenirNext-HeavyItalic
== AvenirNext-Regular
== AvenirNext-Italic
== AvenirNext-MediumItalic
== AvenirNext-UltraLightItalic
== AvenirNext-BoldItalic
== AvenirNext-Heavy
== AvenirNext-Bold
== AvenirNext-UltraLight
2---项目字体---Kohinoor Devanagari
== KohinoorDevanagari-Regular
== KohinoorDevanagari-Light
== KohinoorDevanagari-Semibold
3---项目字体---Times New Roman
== TimesNewRomanPS-ItalicMT
== TimesNewRomanPS-BoldItalicMT
== TimesNewRomanPS-BoldMT
== TimesNewRomanPSMT
4---项目字体---Gill Sans
== GillSans-Italic
== GillSans-SemiBold
== GillSans-UltraBold
== GillSans-Light
== GillSans-Bold
== GillSans
== GillSans-SemiBoldItalic
== GillSans-BoldItalic
== GillSans-LightItalic
5---项目字体---Kailasa
== Kailasa-Bold
== Kailasa
6---项目字体---Bradley Hand
== BradleyHandITCTT-Bold
7---项目字体---PingFang HK
== PingFangHK-Medium
== PingFangHK-Thin
== PingFangHK-Regular
== PingFangHK-Ultralight
== PingFangHK-Semibold
== PingFangHK-Light
8---项目字体---Savoye LET
== SavoyeLetPlain
9---项目字体---Odin Rounded
== Odin-Bold
10---项目字体---Trebuchet MS
== TrebuchetMS-Bold
== TrebuchetMS-Italic
== Trebuchet-BoldItalic
== TrebuchetMS
11---项目字体---Baskerville
== Baskerville-SemiBoldItalic
== Baskerville-SemiBold
== Baskerville-BoldItalic
== Baskerville
== Baskerville-Bold
== Baskerville-Italic
12---项目字体---Futura
== Futura-CondensedExtraBold
== Futura-Medium
== Futura-Bold
== Futura-CondensedMedium
== Futura-MediumItalic
13---项目字体---Arial Hebrew
== ArialHebrew-Bold
== ArialHebrew-Light
== ArialHebrew
14---项目字体---Bodoni 72
== BodoniSvtyTwoITCTT-Bold
== BodoniSvtyTwoITCTT-BookIta
== BodoniSvtyTwoITCTT-Book
15---项目字体---Hoefler Text
== HoeflerText-Italic
== HoeflerText-Black
== HoeflerText-Regular
== HoeflerText-BlackItalic
16---项目字体---Optima
== Optima-ExtraBlack
== Optima-BoldItalic
== Optima-Italic
== Optima-Regular
== Optima-Bold
17---项目字体---Futura MdCn BT
== FuturaBT-MediumCondensed
18---项目字体---DIN Condensed
== DINCondensed-Bold
19---项目字体---Noto Nastaliq Urdu
== NotoNastaliqUrdu
20---项目字体---Charter
== Charter-BlackItalic
== Charter-Bold
== Charter-Roman
== Charter-Black
== Charter-BoldItalic
== Charter-Italic
21---项目字体---Heiti TC
22---项目字体---Geeza Pro
== GeezaPro-Bold
== GeezaPro
23---项目字体---Bodoni Ornaments
== BodoniOrnamentsITCTT
24---项目字体---Kohinoor Telugu
== KohinoorTelugu-Regular
== KohinoorTelugu-Medium
== KohinoorTelugu-Light
25---项目字体---Helvetica Neue
== HelveticaNeue-UltraLightItalic
== HelveticaNeue-Medium
== HelveticaNeue-MediumItalic
== HelveticaNeue-UltraLight
== HelveticaNeue-Italic
== HelveticaNeue-Light
== HelveticaNeue-ThinItalic
== HelveticaNeue-LightItalic
== HelveticaNeue-Bold
== HelveticaNeue-Thin
== HelveticaNeue-CondensedBlack
== HelveticaNeue
== HelveticaNeue-CondensedBold
== HelveticaNeue-BoldItalic
26---项目字体---Party LET
== PartyLetPlain
27---项目字体---Symbol
== Symbol
28---项目字体---Bangla Sangam MN
29---项目字体---Hiragino Sans
== HiraginoSans-W3
== HiraginoSans-W6
30---项目字体---Hiragino Maru Gothic ProN
== HiraMaruProN-W4
31---项目字体---Cochin
== Cochin-Italic
== Cochin-Bold
== Cochin
== Cochin-BoldItalic
32---项目字体---Euphemia UCAS
== EuphemiaUCAS
== EuphemiaUCAS-Italic
== EuphemiaUCAS-Bold
33---项目字体---Academy Engraved LET
== AcademyEngravedLetPlain
34---项目字体---Helvetica
== Helvetica-Oblique
== Helvetica-BoldOblique
== Helvetica
== Helvetica-Light
== Helvetica-Bold
== Helvetica-LightOblique
35---项目字体---American Typewriter
== AmericanTypewriter-CondensedBold
== AmericanTypewriter-Condensed
== AmericanTypewriter-CondensedLight
== AmericanTypewriter
== AmericanTypewriter-Bold
== AmericanTypewriter-Semibold
== AmericanTypewriter-Light
36---项目字体---Didot
== Didot-Bold
== Didot
== Didot-Italic
37---项目字体---Courier New
== CourierNewPS-ItalicMT
== CourierNewPSMT
== CourierNewPS-BoldItalicMT
== CourierNewPS-BoldMT
38---项目字体---Courier
== Courier-BoldOblique
== Courier-Oblique
== Courier
== Courier-Bold
39---项目字体---Rockwell
== Rockwell-Italic
== Rockwell-Regular
== Rockwell-Bold
Xcode 项目工程的结构
这是我常用的项目工程结构,其中包含了 Pods.
ProjectName/
Sourcecode 代码
/M 模型
/V 视图
/C 控制器
External 第三方引用,不管是自己写的类库和其它公司的都称第三方
Supporting Files 默认的一些文件放在这里,比如 main.m Appdelegate.h/m Info.plist
Res 图形素材
Assets.xcassets
Products
Pods
Frameworks
Pods
有时候项目小,不会使用 MVC 分开,那么就会用 Section 的方式,只要变更 Sourcecode里面的内容即可
Sourcecode 代码
/Section1 板块1
/Section2 板块2
iOS 中传值的问题
在 iOS 开发中,两界面之间的传值是常有的事情,传值的方式也有很多,比如 NSUserDefaults,再比如代理传值。
这里简单介绍下用代理传值
开发语言 Objective-C
需求说明 创建两个 ViewController,分别叫着 ViewController 和 SecondView,实现把 SecondView 里面一个 TextField 的值传到 ViewController 里的 Label 中。
步骤和主要代码
创建两个 ViewController,并且分别按需求命名
ViewController 的头文件代码如下
//引入 SecondView
#import "SecondView.h"
@interface ViewController :UIViewController<SecondViewDelegate>
//接受传值的 label
@property (nonatomic, retain) UILabel *lbValue;
@property (nonatomic, retain) UIButton *btnClick;
@end
ViewController 的 m 文件代码如下
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
_lbValue = [[UILabel alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, 30)];
_lbValue.textColor = [UIColor blackColor];
_lbValue.textAlignment = NSTextAlignmentCenter;
_lbValue.text = @"Defult Text";
[self.view addSubview:_lbValue];
_btnClick = [[UIButton alloc] initWithFrame:CGRectMake(10, 100, self.view.frame.size.width - 20, 44)];
[_btnClick setBackgroundColor:[UIColor blackColor]];
[_btnClick addTarget:self action:@selector(actionClick) forControlEvents:UIControlEventTouchUpInside];
[_btnClick setTitle:@"Go to Second" forState:UIControlStateNormal];
[_btnClick setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.view addSubview:_btnClick];
}
\- (void)actionClick {
SecondView *nextView = [[SecondView alloc] init];
// 设置代理到 nextView
nextView.delegate = self;
[self presentViewController:nextView animated:YES completion:nil];
}
\- (void)passValue:(NSString *)value{
// 改变 label 的值
_lbValue.text = value;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
SecondView.h 的部分代码
#import <UIKit/UIKit.h>
// 定义代理协议,实现传值代理
@protocol SecondViewDelegate <NSObject>
// 必须实现的用来传值的协议方法,
- (void)passValue:(NSString *)value;
@end
@interface SecondView : UIViewController
// 此处利用协议来定义代理
@property (nonatomic, unsafe_unretained) id<SecondViewDelegate> delegate;
@property (nonatomic, retain) UITextField *tfValue;
@property (nonatomic, retain) UIButton *btnPass;
@end
SecondView.m 的部分代码
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
_tfValue = [[UITextField alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, 30)];
_tfValue.textColor = [UIColor blackColor];
_tfValue.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:_tfValue];
_btnPass = [[UIButton alloc] initWithFrame:CGRectMake(10, 100, self.view.frame.size.width - 20, 44)];
[_btnPass setBackgroundColor:[UIColor blackColor]];
[_btnPass addTarget:self action:@selector(actionClick) forControlEvents:UIControlEventTouchUpInside];
[_btnPass setTitle:@"Pass" forState:UIControlStateNormal];
[_btnPass setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.view addSubview:_btnPass];
}
- (void)actionClick {
// 通过代理传值
[self.delegate passValue:_tfValue.text];
[self dismissViewControllerAnimated:YES completion:nil];
}
这里基本就是代理传值的实现方式。
Url Scheme 使 APP 互相跳转及查看方法
在 iOS 开发中,Url Scheme 使得 app 之间相互跳转变得非常容易。
首先我们需要判断系统中是否安装了待跳转的 app,比如跳转到微信
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"wexin://"]]){
NSLog(@"已经安装");
}
else{
NSLog(@"未安装");
}
如果安装了,则执行
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"weixin://"]];
这样就可以打开微信,那么是怎么知道这里的 wexin://
即 Url Scheme 的呢?
在电脑上用 iTunes 下载你要跳转的 app
进入到这个 app 所在的文件夹,找到这个文件,应该是一个 .ipa 结尾的文件
将 .ipa 改成可解压的格式并解压,比如 .zip,不过现在有些压缩软件也可以直接解压 .ipa
在 Payload 文件夹中会有一个文件,右键这个文件,选择所弹出菜单上的显示包内容选项
找到 Info.plist 文件,并打开,找到 CFBundleURLSchemes 中的 Url Scheme 即可。记得是本 app 的 Url Scheme,可以对照 URL identifier 找到。
更多使用说明,可以去看 Apple Developer Documents。
iOS 版本升级的提醒功能
虽然 Apple 禁止在 App 中提示升级,而且所有在 App 内部提示升级的 App 都无法通过审核,所以绕过审核人员就是这个功能的重点。
远程开启
实现方式是在服务器端设置一个开关,审核人员在审核 App 的时候,通过服务器关闭了版本升级的提醒功能,但上线后开启。
APP 内部实现
实现方式是获取当前测试版本的和当前 Binary 的版本做配对,相同的不提示,不同的则提示。
第三方插件
目前有不少第三方插件完成了这个功能。
需要注意的是,这是违背开发者标准的,所以,这里我只是说明下思路,具体实现自行解决。
iOS 中拍照
拍照功能是应用中常有的,下面介绍两个拍照方式
UIImagepickerController
调用摄像头,再次之前需要设置对应的两个代理 UIImagePickerControllerDelegate 和 UINavigationControllerDelegate 以及初始化 @property (nonatomic, retain) UIImagePickerController *imagePickerController;
UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;
//Determine has a camera, choose from photo library if no.
if(![UIImagePickerController isSourceTypeAvailable:sourceType]) {
sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
_imagePickerController = [[UIImagePickerController alloc] init];
_imagePickerController.delegate = self;
_imagePickerController.sourceType = sourceType;
_imagePickerController.allowsEditing = YES; //Edit
_imagePickerController.showsCameraControls = YES;
[self presentViewController:_imagePickerController animated:NO completion:nil];
UIImagePickerControllerSourceTypeCamera 有三个方法
UIImagePickerControllerSourceTypePhotoLibrary //从图库中选择
UIImagePickerControllerSourceTypeSavedPhotosAlbum //从相册中选择
UIImagePickerControllerSourceTypeCamera //直接调用摄像头拍照
当用户做完成操作后的处理
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
//From the editdimage:UIImagePickerControllerEditedImage, from the original image:UIImagePickerControllerOriginalImage
UIImage *image= [info objectForKey:@"UIImagePickerControllerEditedImage"];
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
//Save to album
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
//More codes
}
这里的 info 是一个字典类型
UIKIT_EXTERN NSString *const UIImagePickerControllerMediaType __TVOS_PROHIBITED //媒体类型
UIKIT_EXTERN NSString *const UIImagePickerControllerOriginalImage __TVOS_PROHIBITED //原始图片
UIKIT_EXTERN NSString *const UIImagePickerControllerReferenceURL NS_AVAILABLE_IOS(4_1) __TVOS_PROHIBITED //原件的 URL
UIKIT_EXTERN NSString *const UIImagePickerControllerEditedImage __TVOS_PROHIBITED //修改后的图片
UIKIT_EXTERN NSString *const UIImagePickerControllerCropRect __TVOS_PROHIBITED //裁剪尺寸
UIKIT_EXTERN NSString *const UIImagePickerControllerMediaURL __TVOS_PROHIBITED //媒体的 URL
UIKIT_EXTERN NSString *const UIImagePickerControllerMediaMetadata NS_AVAILABLE_IOS(4_1) __TVOS_PROHIBITED //如果是拍照的照片,则需要手动保存到本地,系统不会自动保存拍照成功后的照片
在拍照过程中,用户还有可能有取消的操作,那么需要用方法
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker。
AVFoundation
用 AVFoundation 做拍照功能,常是为了自定义拍照的 UI,这里需要说明一下 UIImagepickerController 也可以自定义拍照的 UI。
头文件中引入 #import <AVFoundation/AVFoundation.h>
,并且初始化
@property (nonatomic, strong) AVCaptureDevice *device; //AVCaptureDeviceInput 代表输入设备,他使用AVCaptureDevice 来初始化
@property (nonatomic, strong) AVCaptureDeviceInput *input; //输出图片
@property (nonatomic, strong) AVCaptureStillImageOutput *imageOutput; //session:由他把输入输出结合在一起,并开始启动捕获设备(摄像头)
@property (nonatomic, strong) AVCaptureSession *session; //图像预览层,实时显示捕获的图像
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
示例代码
- (void)viewDidLoad {
[self cameraDistrict];
}
- (void)cameraDistrict {
self.device = [self cameraWithPosition:AVCaptureDevicePositionFront]; // AVCaptureDevicePositionBack 后置摄像头 AVCaptureDevicePositionFront 前置摄像头
self.input = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:nil];
self.imageOutput = [[AVCaptureStillImageOutput alloc] init];
self.session = [[AVCaptureSession alloc] init];
self.session.sessionPreset = AVCaptureSessionPreset640x480; // 自定义获取的图片的大小 AVCaptureSessionPreset320x240 AVCaptureSessionPreset352x288 AVCaptureSessionPreset640x480 AVCaptureSessionPreset960x540 AVCaptureSessionPreset1280x720 AVCaptureSessionPreset1920x1080 AVCaptureSessionPreset3840x2160
//输入输出设备结合
if ([self.session canAddInput:self.input]) {
[self.session addInput:self.input];
}
if ([self.session canAddOutput:self.imageOutput]) {
[self.session addOutput:self.imageOutput];
}
//预览层的生成
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
self.previewLayer.frame = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height-64);
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:self.previewLayer];
//设备取景开始
[self.session startRunning];
if ([_device lockForConfiguration:nil]) {
//自动闪光灯,
if ([_device isFlashModeSupported:AVCaptureFlashModeAuto]) {
[_device setFlashMode:AVCaptureFlashModeAuto];
}
[_device unlockForConfiguration];
}
}
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for ( AVCaptureDevice *device in devices )
if ( device.position == position ){
return device;
}
return nil;
}
- (void)takePhotos {
AVCaptureConnection *conntion = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
if (!conntion) {
//提示操作
return;
}
[self.imageOutput captureStillImageAsynchronouslyFromConnection:conntion completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer == nil) {
return ;
}
_imgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
[self.session stopRunning];
}];
}
总体来说,上面代码停容易理解的,就不一一解释了。
AFNetworking Post 复杂的 Json
AFNetworking 是 iOS 下一个非常好用的类库,一般它在做 POST 请求的时候,单一 Json 格式较多,如下
NSDictionary *params = @{@"key0":"value0", @"key1":"value1", @"key2":"value2"};
[manager POST:URL_REQUEST parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
但有时候在 Json 会相对复杂点,比如
{
"key0":"value0",
"keys":[
{
"key1":"value1",
"key2":"value2"
},
{
"key1":"value1",
"key2":"value2"
},
{
"key1":"value1",
"key2":"value2"
},
{
"key1":"value1",
"key2":"value2"
}
]
}
这时候就需要构造这部分参数,最简单的方法,循环
NSMutableArray *paramArrays = [NSMutableArray array];
for (int i = 0; i < _keycontent.count ; i++ ) {
GCShoppingCartProductModel *model = _keycontent[i];
NSDictionary *temp = @{@"key1":"value1",@"key2":"value2"};
[paramArrays addObject:temp];
}
NSDictionary *params = @{@"key0":"value0",@"keys":paramArrays};
至于其他请求部分还是一样。
根据经纬度计算距离
手动计算
#define PI 3.1415926
+(double) LantitudeLongitudeDist:(double)lon1 other_Lat:(double)lat1 self_Lon:(double)lon2 self_Lat:(double)lat2{
double er = 6378137; // 6378700.0f;
//ave. radius = 6371.315 (someone said more accurate is 6366.707)
//equatorial radius = 6378.388
//nautical mile = 1.15078
double radlat1 = PI*lat1/180.0f;
double radlat2 = PI*lat2/180.0f;
//now long.
double radlong1 = PI*lon1/180.0f;
double radlong2 = PI*lon2/180.0f;
if( radlat1 < 0 ) radlat1 = PI/2 + fabs(radlat1);// south
if( radlat1 > 0 ) radlat1 = PI/2 - fabs(radlat1);// north
if( radlong1 < 0 ) radlong1 = PI*2 - fabs(radlong1);//west
if( radlat2 < 0 ) radlat2 = PI/2 + fabs(radlat2);// south
if( radlat2 > 0 ) radlat2 = PI/2 - fabs(radlat2);// north
if( radlong2 < 0 ) radlong2 = PI*2 - fabs(radlong2);// west
//spherical coordinates x=r*cos(ag)sin(at), y=r*sin(ag)*sin(at), z=r*cos(at)
//zero ag is up so reverse lat
double x1 = er * cos(radlong1) * sin(radlat1);
double y1 = er * sin(radlong1) * sin(radlat1);
double z1 = er * cos(radlat1);
double x2 = er * cos(radlong2) * sin(radlat2);
double y2 = er * sin(radlong2) * sin(radlat2);
double z2 = er * cos(radlat2);
double d = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));
//side, side, side, law of cosines and arccos
double theta = acos((er*er+er*er-d*d)/(2*er*er));
double dist = theta*er;
return dist;
}
iOS自带
CLLocation *orig=[[[CLLocation alloc] initWithLatitude:[mainDelegate.latitude_self doubleValue] longitude:[mainDelegate.longitude_self doubleValue]] autorelease];
CLLocation* dist=[[[CLLocation alloc] initWithLatitude:[tmpNewsModel.latitude doubleValue] longitude:[tmpNewsModel.longitude doubleValue] ] autorelease];
CLLocationDistance kilometers=[orig distanceFromLocation:dist]/1000;
NSLog(@"距离:",kilometers);
Label 上文字显示不一样
// 创建Attributed
NSMutableAttributedString *noteStr = [[NSMutableAttributedString alloc] initWithString:_label.text];
// 需要改变的第一个文字的位置
NSUInteger firstLoc = [[noteStr string] rangeOfString:@"金"].location + 1;
// 需要改变的最后一个文字的位置
NSUInteger secondLoc = [[noteStr string] rangeOfString:@"元"].location;
// 需要改变的区间
NSRange range = NSMakeRange(firstLoc, secondLoc - firstLoc);
// 改变颜色
[noteStr addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:range];
// 改变字体大小及类型
[noteStr addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"Helvetica-BoldOblique" size:27] range:range];
// 为label添加Attributed
[_label setAttributedText:noteStr];
iOS 判断 uiscrollview 是向上滚动
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
int currentPostion = scrollView.contentOffset.y;
if (currentPostion - _lastPosition > 20 && currentPostion > 0) {
_lastPosition = currentPostion;
NSLog(@"ScrollUp now");
[self hideTabBar:YES];
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
else if ((_lastPosition - currentPostion > 20) && (currentPostion <= scrollView.contentSize.height-scrollView.bounds.size.height-20) )
{
_lastPosition = currentPostion;
NSLog(@"ScrollDown now");
[self hideTabBar:NO];
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
}
倒计时
NStimer
secondsCountDown = 60;
countDownTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeFireMethod) userInfo:nil repeats:YES];
-(void)timeFireMethod{
secondsCountDown--;
if(secondsCountDown==0){
[countDownTimer invalidate];
}
}
GCD
__block int timeout=300; //倒计时时间
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
dispatch_source_set_event_handler(_timer, ^{
if(timeout<=0){ //倒计时结束,关闭
dispatch_source_cancel(_timer);
dispatch_release(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
//设置界面的按钮显示 根据自己需求设置
。。。。。。。。
});
}else{
int minutes = timeout / 60;
int seconds = timeout % 60;
NSString *strTime = [NSString stringWithFormat:@"%d分%.2d秒后重新获取验证码",minutes, seconds];
dispatch_async(dispatch_get_main_queue(), ^{
//设置界面的按钮显示 根据自己需求设置
。。。。。。。。
});
timeout--;
}
});
dispatch_resume(_timer);
iOS 上为 app 设置字体大小
iOS 上为 app 设置字体大小 https://www.theverge.com/22580423/ios-15-iphone-text-size-how-to-control-center
苹果的开发者资源
苹果的开发者资源,还是弄得挺好的 https://developer.apple.com/design/resources/
iPad Pro 连接键盘和鼠标之后出现蓝色的框问题
这个问题的确是很烦人的,https://discussionschinese.apple.com/thread/251581565.
> 可在 Twitter/X 上评论该篇文章或在下面留言(需要有 GitHub 账号)