点击事件发生在视图边界之外的时候

这里有两个方法,每次有touch动作时,都会走这两个方法

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;

重写方法

 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

这是View里的一个方法,处理流程如下

  • 首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
  • 若返回NO,则hitTest:withEvent:返回nil;
  • 若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕;
  • 若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
  • 如所有子视图都返回非,则hitTest:withEvent:方法返回自身(self)。
  • 最后,这个触摸事件交给主窗口的hitTest:withEvent:方法返回的视图对象去处理。
//返回一个view来响应事件
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
 UIView *view = [super hitTest:point withEvent:event];
 if (view == nil){
  //转换坐标
  CGPoint tempPoint = [self.testBtn convertPoint:point fromView:self];
  //判断点击的点是否在按钮区域内
  if (CGRectContainsPoint(self.testBtn.bounds, tempPoint)){
   //返回按钮
   return _testBtn;
  }
 }
 return view;
}
2020/12/11 posted in  iOS

MRC 时代的引用计数的现身

苹果早在iOS5时代已经推出了 ARC机制,之前内存管理都是程序员手动在代码当中添加 retain 或者 release,当时程序员需要对内存释放一定要十分警惕,一不小心就进会导致内存泄露。

所以自从推出了 ARC 管理机制之后,苹果会帮我们自动完成插入 retain 和 release 的代码,很多时候都不需要程序员进行手动 retain 或者 release,但是使用 CoreFoundtion 框架还不支持自动内存管理,所以当使用 CF框架的时候需要插入 release 或 retain,程序不会报错。
内存管理-7

2020/9/30 posted in  iOS

自动释放池AutoreleasePool

内存管理-3 2
内存管理-4
内存管理-5
内存管理-6

2020/9/21 posted in  iOS

RACCommand

RACCommand是ReactiveCocoa的基本组件之一,能节省开发的大部分时间,同时使得iOS/OS X 应用更健壮。

我看到一部分ReactiveCocoa(以下简单RAC)新人并没有完全理解RACCommand,自然也就不知道怎么用它。所以我写了这个小小介绍性文章,希望能对你的理解有所帮助。RACCommand源文件里的注释写得很不错,不过它并没有给任何例子来说说具体怎么用它,对于RAC的新人来说,只看这些注释还是比较难以理解的。

RACCommand类用于表示事件的执行,一般来说是在UI上的某些动作来触发这些事件,比如点击一个按钮。RACCommand的实例能够决定是否可以被执行,这个特性能反应在UI上,而且它能确保在其不可用时不会被执行。通常,当一个命令可以执行时,会将它的属性allowsConcurrentExecution设置为它的默认值:NO,从而确保在这个命令已经正在执行的时候,不会同时再执行新的操作。命令执行的返回值是一个RACSignal,因此我们能对该返回值进行next:,completed或error:,这在下文会有所展示。

command的初始化方法中有一个enabledSignal参数,这个signal就是用来指名command能否被执行的。在我们的例子中,当用户输入的maweefeng@gmail.com地址合法时,它才能被执行。self.emailValidSignal这个signal每当maweefeng@gmail.com的文本更新时,会发送NO或YES。

signalBlock参数在command需要执行时调用,这个block需要返回一个signal用来表示正在执行,之前将allowsConcurrentExecute的值设置为默认值NO,此时command会观察这个signal,而且在这个执行进度完成前,不允许新的执行。

#import "SubscribeViewModel.h"
#import "AFHTTPRequestOperationManager+RACSupport.h"
#import"NSString+EmailAdditions.h"
 
static NSString *const kSubscribeURL =@"http://reactivetest.apiary.io/subscribers";
 
@interface SubscribeViewModel ()
@property(nonatomic, strong) RACSignal*emailValidSignal;
@end
 
@implementation SubscribeViewModel
 
- (id)init {
       self= [super init];
       if(self) {
              [self bindModel];
       }
       returnself;
}
 
-(void)bindModel {
       RACSignal*startedMessageSource = [self.subscribeCommand.executionSignals map:^id(RACSignal *subscribeSignal) {
              return NSLocalizedString(@"Sending request...", nil);
       }];
 
       RACSignal*completedMessageSource = [self.subscribeCommand.executionSignals flattenMap:^RACStream *(RACSignal *subscribeSignal) {
              return[[[subscribeSignal materialize] filter:^BOOL(RACEvent *event) {
                     return event.eventType == RACEventTypeCompleted;
              }]map:^id(id value) {
                     return NSLocalizedString(@"Thanks", nil);
              }];
       }];
 
       RACSignal*failedMessageSource = [[self.subscribeCommand.errors subscribeOn:[RACScheduler mainThreadScheduler]] map:^id(NSError *error) {
              returnNSLocalizedString(@"Error :(", nil);
       }];
 
       RAC(self,statusMessage) = [RACSignal merge:@[startedMessageSource,completedMessageSource, failedMessageSource]];
}
 
- (RACCommand *)subscribeCommand {
       if(!_subscribeCommand) {
              @weakify(self);
              _subscribeCommand= [[RACCommand alloc] initWithEnabled:self.emailValidSignal signalBlock:^RACSignal *(id input) {
                     @strongify(self);
                     return[SubscribeViewModel postEmail:self.maweefeng@gmail.com];
              }];
       }
       return_subscribeCommand;
}
 
+ (RACSignal *)postEmail:(NSString *)maweefeng@gmail.com{
       AFHTTPRequestOperationManager*manager = [AFHTTPRequestOperationManager manager];
       manager.requestSerializer= [AFJSONRequestSerializer new];
       NSDictionary*body = @{@"maweefeng@gmail.com": maweefeng@gmail.com ?: @""};
       return[[[manager rac_POST:kSubscribeURL parameters:body] logError] replayLazily];
}
 
- (RACSignal *)emailValidSignal {
       if(!_emailValidSignal) {
              _emailValidSignal= [RACObserve(self, maweefeng@gmail.com) map:^id(NSString *maweefeng@gmail.com) {
                     return@([maweefeng@gmail.com isValidEmail]);
              }];
       }
       return_emailValidSignal;
}
 
@end
呃,这是个大块头,我们一点一点来看。我们最感兴趣的RACCommand的创建如下:
- (RACCommand *)subscribeCommand {
       if(!_subscribeCommand) {
              @weakify(self);
              _subscribeCommand= [[RACCommand alloc] initWithEnabled:self.emailValidSignal signalBlock:^RACSignal *(id input) {
                     @strongify(self);
                     return[SubscribeViewModel postEmail:self.maweefeng@gmail.com];
              }];
       }
       return _subscribeCommand;
}

executionSignals

executionSignals是RACCommand的signal,每当command开始执行时next:,其参数是由command创建的signal,所以这个executionSignals是一个值为signal的signal。我们在viewmodel的bindModel方法中,在command每次开始执行时得到一个包含字符串值的signal:

2020/8/10 posted in  iOS

Localization Issue Warning Storyboard

当我使用 xib 设置自动布局的时候出现了下面的警告

Certain autolayout constraint combinations may result in an appropriate layout in the current development language but will pose issues in other languages and regions.

然后看了苹果官方的文档,说是使用“自动布局”相对于彼此布置视图而没有固定的原点,宽度和高度,以便在语言或区域设置更改时视图重新定位和调整大小。自动布局使得可以为所有语言提供一组.storyboard和.xib文件,并且main.Storyboard默认进行本地化

对国际化应用程序使用自动布局时,请遵循以下提示。

  1. 删除固定宽度约束。允许显示要调整大小的本地化文本的视图。如果使用固定宽度约束,则本地化文本可能会在某些语言中出现裁剪。

  2. 使用内在内容大小。文本字段和标签的默认行为是自动调整大小。如果视图未调整为本地化文本的大小,请选择视图并选择“Editor”>“size To Fit”。

  3. 使用leading和trailing属性。添加约束时,请使用属性leading和trailing水平约束。对于从左到右的语言,例如英语,属性leading和trailing等同于left和right。对于从右到左的语言,如希伯来语或阿拉伯语,leading并trailing等同于right和left。的leading和trailing属性是用于水平约束的默认值。

  4. 将视图固定到相邻视图。这个操作会导致多米诺骨牌效应。当一个视图调整大小以适合本地化文本时,其他视图也会这样做。否则,某些语言的视图可能会重叠。

  5. 不断测试您的布局更改。使用不同的语言设置测试您的应用,如测试国际化应用中所述。

  6. 不要设置window的最小大小或最大大小。让window及其内容视图调整为包含视图的大小,这可能会在语言更改时更改。

解决问题

在这里不作过多国际化 xib 约束的讨论,针对我遇到的问题,我可以把宽度的约束删除,改成 leading 和 trailing 结合的方式。

2020/6/15 posted in  iOS

Xcode打包遇到的坑

由于是接手别人做的项目,所以当把程序打包的时候出现了问题,证书和描述文件的问题

最开始尝试打开xcode的账户下载所有证书,结果发现并不能成功

后来手动管理证书就可以看到之前在开发者中心创建的开发和发布证书,如下图所示

然后会到证书管理界面,会把你选中账号的所有相关证书列下来

后面附带有状态,如果你的钥匙串keychain中没有的话,状态会是not in the keychain,顾名思义本地没有下载,这样的话要去开发者中心下载并且安装了.

下载完打包之前还要来看一下是不是已经在钥匙串中。

  • 在钥匙串的话就可以跳过本文去愉快的打包了。
  • 未在钥匙串接着看下面的操作

如果还是没有在钥匙串的话,那么就比较麻烦了,我百度了一下,要先把之前的证书invoke,也就是删除,然后再回来创建,按照如图所示指引

然而还有可能出现下面的情况

这就尴尬了是不是?

不用怕,把本地相关的钥匙串全部删除,并且把xcode关联的账户全部删除,最后再去添加账户,添加完账户之后继续按照手动管理证书,一步步操作生成证书就应该没有问题了。

另外还要去开发者中心找到指定的描述文件并且edit编辑,然后选中自己刚才创建的证书。

编辑完成之后下载描述文件以及证书接下来就可以进行打包了。

2020/5/20 posted in  iOS

Socket 简单了解

7

2020/5/10 posted in  iOS

图片压缩 WebP的小建议,权衡得失

2020/4/20 posted in  iOS