142. 如何在 Category 中定义简单属性?
通常我们会在类别中用 objc_setAssociatedObject 来定义一个属性。但是 objc_setAssociatedObject 方法定义如下:
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
它的第三个参数 value 为 id 类型,也就是说,它只能定义对象类型属性。那我们要定义简单类型比如 CGFloat 或 int 属性时怎么办?
假设我们定义一个 CGFloat 属性:
@property(nonatomic,assign)CGFloat rollSpeed
那么我们需要这样合成它的 setter 方法:
- (void)setRollSpeed:(CGFloat)rollSpeed{
objc_setAssociatedObject(self, @selector(rollSpeed), @(rollSpeed), OBJC_ASSOCIATION_ASSIGN);
}
也就是说这个属性的背后实际上用一个 NSNumber 对象的关联对象存储。这样合成 getter 方法时也要访问这个 NSNumber 对象并转成 double 来获取:
-(CGFloat)rollSpeed{
NSNumber* number = objc_getAssociatedObject(self, @selector(rollSpeed));
if(number != nil){
return number.doubleValue;
}
return 0;
}
143. 如何查看某段内存地址对应的代码?
在 lldb 中使用:
image lookup --address 0x0000000104c25550
144. 如何在变量等于某个字符串时中断程序?
使用条件断点,条件设置为一个 BOOL 表达式。注意判断字符串是否相等不要使用 == ,而是使用 isEqualToString:
[methodName isEqualToString:@"callbackJS:result:"]
注意修改条件后,需要重新运行程序。
145. 为什么 setNavigationBarHidden 不生效?
请确认你是在 viewWillAppear/viewDidAppear 中,而不是在 viewDidLoad 中调用 setNavigationBarHidden 。
146. 如何截去字符串前后空格?
NSString *trimmedString = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
147. 为什么 pathForResource 对有的文件会返回 nil?
对于有的文件类型,比如 .m4a、.xml,Xcode 不会将文件自动添加到 bundle。请在 File Inspector 中将这个文件添加到 bundle。
148. 如何播放gif动画?
NSArray* gifArray = [NSArray arrayWithObjects:
[UIImage imageNamed:@"play1"],
[UIImage imageNamed:@"play2"],
[UIImage imageNamed:@"play3"],
[UIImage imageNamed:@"play4"],
[UIImage imageNamed:@"play5"],
[UIImage imageNamed:@"play6"],
[UIImage imageNamed:@"play7"],
[UIImage imageNamed:@"play8"],
[UIImage imageNamed:@"play9"],
[UIImage imageNamed:@"play10"],
[UIImage imageNamed:@"play11"],
[UIImage imageNamed:@"play12"],
[UIImage imageNamed:@"play13"],
[UIImage imageNamed:@"play14"],
nil];
UIImageView* ivWavePeak = [[UIImageView alloc] initWithFrame:self.bounds];
ivWavePeak.animationImages = gifArray; //动画图片数组
ivWavePeak.animationDuration = 1.5; //执行一次完整动画所需的时长
ivWavePeak.animationRepeatCount = 0; //动画重复次数,无限循环
149. 如何等待多个异步操作完成再执行某些动作?
dispatch_group_t group = dispatch_group_create();
NSMutableDictionary<NSString*,NSData*>* urls = [NSMutableDictionary new];
for(PHAsset* photo in assetArray){
dispatch_group_enter(group);
[[PHImageManager defaultManager] requestImageForAsset:photo targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:nil resultHandler:^(UIImage *result, NSDictionary *info) {
NSString* fileurl = info[@"PHImageFileURLKey"];
NSData* data = UIImageJPEGRepresentation(result,0.99);
urls[fileurl]= data;
dispatch_group_leave(group);
}];
}
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_notify(group, queue, ^{
……
});
150. 为什么 viewDidLoad 方法不调用?
这个 ViewController 有一个 Category,把 viewDidLoad 方法覆盖了,所以调用的是 Category 的 viewDidLoad 方法。
151. 为什么当 imagePickerController 解散后页面变成了空白?
假设弹出 imagePickerController 的视图控制器名为 A,当 imagePickerController 显示时,会 retain A(即 presentingViewController),于是 A 的引用计数为 2。由于 imagePickerController 会遮住 A,A 会被 ARC 系统自动释放(因为它不需要显示了),于是引用计数变成了 2-1 = 1。当 imagePickerController 解散时,它会被自动释放,它的 presentingViewController 也会 release,于是 A 的引用计数变成了 0。A 被释放。
因此解决办法就是强引用 imagePickerController 对象,让它不会在方法结束时自动释放。即在 A 的类声明中定义一个 retain 属性引用 imagePickerController 对象。但这会导致引用循环(retain cycle)问题。即 imagePickerController 强引用 A,而 A 又强引用了 imagePickerController。为了避免这个问题,我们需要在解散 imagePickerController 的时候手动 release 它一次:
[self dismissViewControllerAnimated:YES completion:^(){
self.imagePicker= nil;
}];
152. 为什么对 UIView 截图得到模糊的图?
将 UIGraphicsBeginImageContext(size); 一句替换为:
UIGraphicsBeginImageContextWithOptions(shotView.bounds.size, NO, [[UIScreen mainScreen] scale]);
为什么毛玻璃效果(UIBlurEffect)在有的设备上不生效?
注意,是有的设备没效果(iOS 8 以上),大部分设备上还是生效的。对于没效果的设备,请确认“辅助功能\增强对比度”中的“降低透明度”开关没有被打开。在代码中,可以用 UIAccessibilityIsReduceTransparencyEnabled 来判断是否生效:
//方法一:系统方法,iOS8及以上可用
if (!UIAccessibilityIsReduceTransparencyEnabled()) {
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc]initWithEffect:blurEffect];
blurEffectView.frame = _imageView.bounds;
[_imageView addSubview:blurEffectView];
}
//方法二:Core Image
UIImageView *blurImageView = [[UIImageView alloc]initWithFrame:_imageView.bounds];
blurImageView.image = [self blur:[UIImage imageNamed:@"1.jpg"]];
[_imageView addSubview:blurImageView];
其中,Core Image 生成毛玻璃效果的方法如下:
//生成一张毛玻璃图片
- (UIImage*)blur:(UIImage*)theImage
{
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *inputImage = [CIImage imageWithCGImage:theImage.CGImage];
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[filter setValue:inputImage forKey:kCIInputImageKey];
[filter setValue:[NSNumber numberWithFloat:15.0f] forKey:@"inputRadius"];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGImageRef cgImage = [context createCGImage:result fromRect:[inputImage extent]];
UIImage *returnImage = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
return returnImage;
}
为什么 CIDetector 有的图不识别?
原图太大,导致识别率过低。可以压缩一下原图再进行识别:
UIImage* resizeImage = [image scaledToScale:0.2];
CIImage *ciImage = [[CIImage alloc] initWithCGImage:resizeImage.CGImage options:nil];
//创建探测器
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];
NSArray *feature = [detector featuresInImage:ciImage];
//取出探测到的数据
for (CIQRCodeFeature *result in feature) {
content = result.messageString; // TON131605BBBB050
[self stringChages:content];
}
155. 为什么用 setNavigationBarHidden: 无法显示导航栏?
请检查是不是在代码中强制将 navigationBar 设置为隐藏了:
self.navigationController.navigationBar.hidden = YES;
将这句代码注释了。不应该直接设置 navigationBar 的 hidden 属性,改用 setNavigationBarHidden 方法隐藏导航栏。
回到目录
156. 访问https出错:In order to validate a domain name for self signed certificates, you MUST use pinning
设置两个安全设置:
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesDomainName = NO;
157.我的设备数达到了上限,我又急需要增加新的设备怎么办?
对此你可以给苹果的技术客服发邮件要求他们帮助我们删除所有的设备,并且恢复到增加100个测试设备的名额。具体做法是访问https://developer.apple.com/contact/, 单击“Program Benefits”按钮,然后在新出来的提交页面中将需求添上。之后苹果会发邮件告诉你处理结果,你可能需要打电话过去和他们沟通一些细节。在沟通完成之后,苹果就可以立即帮助你把状态修改到“可删除设备来增加测试设备名额”。这样,你就可以选择性的删除一些不需要的设备来释放一些名额了。
回到目录
158.知道中文字符串对应的 utf8 数值,如何正确输出这段中文?
比如,中文“精品”的 unicode(utf8) 值为“\U7cbe\U54c1”,如何将 \U7cbe\U54c1 正确的中文“精品”输出出来?答案是:NSString => NSData => NSString
NSString *s = @"\\U7cbe\\U54c1";
NSData *data=[s dataUsingEncoding:NSUTF8StringEncoding];
s = [[NSString alloc] initWithData:data encoding:NSNonLossyASCIIStringEncoding] ;
NSLog(@"%@",s);
注意斜杠“\”在 NSString 中要用两道斜杠“\”来进行转义。
159. 如何禁用 CALayer 的隐式动画效果?
当对非Root Layer的部分属性进行修改时,默认会自动产生一些动画效果,而这些属性称为Animatable Properties(可动画属性)。但有时候我们不需要这些隐式动画效果,该怎么关闭它呢?
比如当我们修改一个 CALayer 的 frame 时,默认会有一个框架变形的动画(iOS 10.3)。如果我们不需要这个效果,可以将 CATransaction 的 disableActions 属性设置为 YES:
[CATransaction begin];
[CATransaction setDisableActions:YES];
barMaskLayer.frame = CGRectMake(_leftGap, _topGap, width*_percent, _barHeight);
[CATransaction commit];