This commit is contained in:
2025-11-10 15:38:30 +08:00
parent 97316c7989
commit 1cdc17b710
18 changed files with 337 additions and 20 deletions

View File

@@ -234,7 +234,7 @@ static CGFloat KEYBOARDHEIGHT = 256 + 20;
// 使 App Scheme // 使 App Scheme
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@@//login?src=keyboard", KB_APP_SCHEME]]; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@@//login?src=keyboard", KB_APP_SCHEME]];
if (!url) return; if (!url) return;
__weak typeof(self) weakSelf = self; KBWeakSelf
[self.extensionContext openURL:url completionHandler:^(__unused BOOL success) { [self.extensionContext openURL:url completionHandler:^(__unused BOOL success) {
// 使 // 使
__unused typeof(weakSelf) selfStrong = weakSelf; __unused typeof(weakSelf) selfStrong = weakSelf;

View File

@@ -259,7 +259,7 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
// 访宿/ // 访宿/
if (![[KBFullAccessManager shared] hasFullAccess]) return; if (![[KBFullAccessManager shared] hasFullAccess]) return;
if (self.pasteboardTimer) return; if (self.pasteboardTimer) return;
__weak typeof(self) weakSelf = self; KBWeakSelf
self.pasteboardTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) { self.pasteboardTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
__strong typeof(weakSelf) self = weakSelf; if (!self) return; __strong typeof(weakSelf) self = weakSelf; if (!self) return;
UIPasteboard *pb = [UIPasteboard generalPasteboard]; UIPasteboard *pb = [UIPasteboard generalPasteboard];

View File

@@ -338,7 +338,6 @@
if (before.length <= 0) { self.backspaceHoldActive = NO; return; } if (before.length <= 0) { self.backspaceHoldActive = NO; return; }
[proxy deleteBackward]; // 1 [proxy deleteBackward]; // 1
// 使 NSTimer
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.06 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.06 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) selfStrong = weakSelf; __strong typeof(weakSelf) selfStrong = weakSelf;

View File

@@ -76,6 +76,7 @@
04890A042EC0BBBB00FABA60 /* KBCategoryTitleImageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04890A012EC0BBBB00FABA60 /* KBCategoryTitleImageCell.m */; }; 04890A042EC0BBBB00FABA60 /* KBCategoryTitleImageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04890A012EC0BBBB00FABA60 /* KBCategoryTitleImageCell.m */; };
04890A052EC0BBBB00FABA60 /* KBCategoryTitleImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04890A032EC0BBBB00FABA60 /* KBCategoryTitleImageView.m */; }; 04890A052EC0BBBB00FABA60 /* KBCategoryTitleImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04890A032EC0BBBB00FABA60 /* KBCategoryTitleImageView.m */; };
049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */; }; 049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */; };
049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20D2EC1CD2800FAB05D /* KBAlert.m */; };
04A9FE0F2EB481100020DB6D /* KBHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97082EB31B14007BD342 /* KBHUD.m */; }; 04A9FE0F2EB481100020DB6D /* KBHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97082EB31B14007BD342 /* KBHUD.m */; };
04A9FE132EB4D0D20020DB6D /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; }; 04A9FE132EB4D0D20020DB6D /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; };
04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */; }; 04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */; };
@@ -266,6 +267,8 @@
04890A032EC0BBBB00FABA60 /* KBCategoryTitleImageView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBCategoryTitleImageView.m; sourceTree = "<group>"; }; 04890A032EC0BBBB00FABA60 /* KBCategoryTitleImageView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBCategoryTitleImageView.m; sourceTree = "<group>"; };
049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = "<group>"; }; 049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = "<group>"; };
049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = "<group>"; }; 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = "<group>"; };
049FB20C2EC1CD2800FAB05D /* KBAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAlert.h; sourceTree = "<group>"; };
049FB20D2EC1CD2800FAB05D /* KBAlert.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAlert.m; sourceTree = "<group>"; };
04A9A67D2EB9E1690023B8F4 /* KBResponderUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBResponderUtils.h; sourceTree = "<group>"; }; 04A9A67D2EB9E1690023B8F4 /* KBResponderUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBResponderUtils.h; sourceTree = "<group>"; };
04A9FE102EB4D0D20020DB6D /* KBFullAccessManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFullAccessManager.h; sourceTree = "<group>"; }; 04A9FE102EB4D0D20020DB6D /* KBFullAccessManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFullAccessManager.h; sourceTree = "<group>"; };
04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFullAccessManager.m; sourceTree = "<group>"; }; 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFullAccessManager.m; sourceTree = "<group>"; };
@@ -544,6 +547,10 @@
048908B82EBDC11200FABA60 /* V */ = { 048908B82EBDC11200FABA60 /* V */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
04FC97072EB31B14007BD342 /* KBHUD.h */,
04FC97082EB31B14007BD342 /* KBHUD.m */,
049FB20C2EC1CD2800FAB05D /* KBAlert.h */,
049FB20D2EC1CD2800FAB05D /* KBAlert.m */,
); );
path = V; path = V;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -968,8 +975,6 @@
04FC970B2EB334F8007BD342 /* UIImageView+KBWebImage.m */, 04FC970B2EB334F8007BD342 /* UIImageView+KBWebImage.m */,
04FC970C2EB334F8007BD342 /* KBWebImageManager.h */, 04FC970C2EB334F8007BD342 /* KBWebImageManager.h */,
04FC970D2EB334F8007BD342 /* KBWebImageManager.m */, 04FC970D2EB334F8007BD342 /* KBWebImageManager.m */,
04FC97072EB31B14007BD342 /* KBHUD.h */,
04FC97082EB31B14007BD342 /* KBHUD.m */,
04A9FE142EB873C80020DB6D /* UIViewController+Extension.h */, 04A9FE142EB873C80020DB6D /* UIViewController+Extension.h */,
04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */, 04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */,
047C655A2EBCD08E0035E841 /* UIView+KBShadow.h */, 047C655A2EBCD08E0035E841 /* UIView+KBShadow.h */,
@@ -1338,6 +1343,7 @@
0477BE002EBC6A330055D639 /* HomeRankVC.m in Sources */, 0477BE002EBC6A330055D639 /* HomeRankVC.m in Sources */,
047C650D2EBC8A840035E841 /* KBPanModalView.m in Sources */, 047C650D2EBC8A840035E841 /* KBPanModalView.m in Sources */,
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */, 043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */,
049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */,
04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */, 04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */,
04C6EABE2EAF86530089C901 /* AppDelegate.m in Sources */, 04C6EABE2EAF86530089C901 /* AppDelegate.m in Sources */,
04FC95F12EB339A7007BD342 /* LoginViewController.m in Sources */, 04FC95F12EB339A7007BD342 /* LoginViewController.m in Sources */,

View File

@@ -34,13 +34,25 @@ static inline __kindof UIWindow *KBActiveWindow(void) {
+ (UIViewController *)kb_topMostViewController { + (UIViewController *)kb_topMostViewController {
UIWindow *window = KBActiveWindow(); UIWindow *window = KBActiveWindow();
UIViewController *root = window.rootViewController; UIViewController *vc = window.rootViewController;
if (!root) return nil; if (!vc) return nil;
UIViewController *top = root; //
while (top.presentedViewController) { while (1) {
top = top.presentedViewController; if ([vc isKindOfClass:UINavigationController.class]) {
vc = ((UINavigationController *)vc).visibleViewController ?: vc;
continue;
}
if ([vc isKindOfClass:UITabBarController.class]) {
vc = ((UITabBarController *)vc).selectedViewController ?: vc;
continue;
}
if (vc.presentedViewController) {
vc = vc.presentedViewController;
continue;
}
break;
} }
return top; return vc;
} }
@end @end

View File

@@ -0,0 +1,75 @@
//
// KBAlert.h
// keyBoard
//
// 系统 UIAlertController 的轻量封装:更易用、更健壮。
// 特性:
// - 任意线程调用;内部切回主线程
// - 自动找到可展示的 VC使用顶层 presented VC
// - Alert 队列:避免“正在展示时再次 present 失败”的崩溃/警告
// - iPad ActionSheet 自动设置 popover 锚点(无需关心 sourceView
// - 常见场景一行调用:提示/确认/输入框/操作表
// - 可选指定展示的 VC如在 Extension 内)
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^KBAlertBoolHandler)(BOOL ok);
typedef void (^KBAlertIndexHandler)(NSInteger index);
typedef void (^KBAlertTextHandler)(NSString * _Nullable text, BOOL ok);
@interface KBAlert : NSObject
/// 指定一个缺省的“用于 present 的 VC”。
/// - 适用App Extension 或自管理容器场景App 内一般无需设置。
/// - 注意:弱引用;随时可被释放。
+ (void)setDefaultPresenter:(nullable __kindof UIViewController *)presenter;
#pragma mark - 简单提示(单按钮)
/// 标准 OK 提示按钮文案默认为“好”或“OK”。
+ (void)showTitle:(nullable NSString *)title message:(nullable NSString *)message;
/// 自定义按钮文案与回调。
+ (void)showTitle:(nullable NSString *)title
message:(nullable NSString *)message
button:(nullable NSString *)button
completion:(dispatch_block_t)completion;
#pragma mark - 确认对话框(双按钮)
/// 默认“取消/确定”按钮,回调 ok=YES 表示点击了确定。
+ (void)confirmTitle:(nullable NSString *)title
message:(nullable NSString *)message
completion:(KBAlertBoolHandler)completion;
/// 自定义按钮文案。
+ (void)confirmTitle:(nullable NSString *)title
message:(nullable NSString *)message
ok:(nullable NSString *)okTitle
cancel:(nullable NSString *)cancelTitle
completion:(KBAlertBoolHandler)completion;
#pragma mark - 输入框(单行)
/// 带单个输入框ok=YES 时返回输入内容。
+ (void)promptTitle:(nullable NSString *)title
message:(nullable NSString *)message
placeholder:(nullable NSString *)placeholder
ok:(nullable NSString *)okTitle
cancel:(nullable NSString *)cancelTitle
keyboardType:(UIKeyboardType)type
configuration:(void (^ _Nullable)(UITextField *tf))config
completion:(KBAlertTextHandler)completion;
#pragma mark - 操作表ActionSheet
/// 操作表index 为点击项序号,按 actions 顺序从 0 开始;取消返回 -1。
+ (void)actionSheetTitle:(nullable NSString *)title
message:(nullable NSString *)message
actions:(NSArray<NSString *> *)actions
cancel:(nullable NSString *)cancelTitle
destructiveIndex:(NSInteger)destructiveIndex // 传入 -1 表示无
fromView:(nullable UIView *)anchorView // iPad 可指定锚点;传 nil 自动居中
completion:(KBAlertIndexHandler)completion;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,224 @@
//
// KBAlert.m
// keyBoard
//
#import "KBAlert.h"
#import <UIKit/UIKit.h>
#import "UIViewController+Extension.h"
@implementation KBAlert
// present
static NSMutableArray<dispatch_block_t> *sQueue;
static BOOL sPresenting = NO;
static __weak UIViewController *sDefaultPresenter = nil; // presenter
#pragma mark - Helpers
+ (void)initialize {
if (self == KBAlert.class) {
sQueue = [NSMutableArray array];
}
}
+ (void)onMain:(dispatch_block_t)blk {
if (NSThread.isMainThread) { blk(); } else { dispatch_async(dispatch_get_main_queue(), blk); }
}
+ (UIViewController *)presentingVC {
// 使 presenter
UIViewController *vc = sDefaultPresenter;
if (!vc) {
vc = [UIViewController kb_topMostViewController];
}
return vc;
}
+ (void)enqueuePresent:(dispatch_block_t)presenter {
[self onMain:^{
[sQueue addObject:[presenter copy]];
if (!sPresenting) { [self _dequeueAndPresentNext]; }
}];
}
+ (void)_dequeueAndPresentNext {
if (sPresenting || sQueue.count == 0) { return; }
sPresenting = YES;
dispatch_block_t blk = sQueue.firstObject;
[sQueue removeObjectAtIndex:0];
blk();
}
// action
+ (void)_markFinishedAndContinue {
// runloop dismiss
dispatch_async(dispatch_get_main_queue(), ^{
sPresenting = NO;
[self _dequeueAndPresentNext];
});
}
// iPad ActionSheet popover
+ (void)configurePopoverIfNeeded:(UIAlertController *)ac anchorView:(UIView *)anchorView inVC:(UIViewController *)vc {
if (ac.preferredStyle != UIAlertControllerStyleActionSheet) { return; }
UIPopoverPresentationController *pop = ac.popoverPresentationController;
if (!pop) { return; }
if (anchorView) {
pop.sourceView = anchorView;
pop.sourceRect = anchorView.bounds;
} else if (vc.view) {
pop.sourceView = vc.view;
CGSize sz = vc.view.bounds.size;
CGRect r = CGRectMake(MAX(0, sz.width * 0.5 - 1), MAX(0, sz.height * 0.5 - 1), 2, 2);
pop.sourceRect = r; //
pop.permittedArrowDirections = 0;
}
}
#pragma mark - Public API
+ (void)setDefaultPresenter:(UIViewController *)presenter { sDefaultPresenter = presenter; }
+ (void)showTitle:(NSString *)title message:(NSString *)message {
[self showTitle:title message:message button:nil completion:nil];
}
+ (void)showTitle:(NSString *)title
message:(NSString *)message
button:(NSString *)button
completion:(dispatch_block_t)completion {
[self enqueuePresent:^{
UIViewController *vc = [self presentingVC];
if (!vc) { // presenter
[self _markFinishedAndContinue];
return;
}
NSString *ok = button ?: (NSLocalizedString(@"OK", nil).length ? NSLocalizedString(@"OK", nil) : @"好");
UIAlertController *ac = [UIAlertController alertControllerWithTitle:(title ?: @"")
message:(message ?: @"")
preferredStyle:UIAlertControllerStyleAlert];
__weak UIAlertController *wac = ac;
UIAlertAction *okAct = [UIAlertAction actionWithTitle:ok style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction * _Nonnull action) {
if (completion) { completion(); }
// alert
[wac dismissViewControllerAnimated:YES completion:nil];
[KBAlert _markFinishedAndContinue];
}];
[ac addAction:okAct];
[vc presentViewController:ac animated:YES completion:nil];
}];
}
+ (void)confirmTitle:(NSString *)title message:(NSString *)message completion:(KBAlertBoolHandler)completion {
[self confirmTitle:title message:message ok:nil cancel:nil completion:completion];
}
+ (void)confirmTitle:(NSString *)title
message:(NSString *)message
ok:(NSString *)okTitle
cancel:(NSString *)cancelTitle
completion:(KBAlertBoolHandler)completion {
[self enqueuePresent:^{
UIViewController *vc = [self presentingVC];
if (!vc) { [self _markFinishedAndContinue]; return; }
NSString *ok = okTitle ?: @"确定";
NSString *cancel = cancelTitle ?: @"取消";
UIAlertController *ac = [UIAlertController alertControllerWithTitle:(title ?: @"")
message:(message ?: @"")
preferredStyle:UIAlertControllerStyleAlert];
__weak UIAlertController *wac = ac;
UIAlertAction *cancelAct = [UIAlertAction actionWithTitle:cancel style:UIAlertActionStyleCancel handler:^(__unused UIAlertAction * _Nonnull a) {
if (completion) { completion(NO); }
[wac dismissViewControllerAnimated:YES completion:nil];
[KBAlert _markFinishedAndContinue];
}];
UIAlertAction *okAct = [UIAlertAction actionWithTitle:ok style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction * _Nonnull a) {
if (completion) { completion(YES); }
[wac dismissViewControllerAnimated:YES completion:nil];
[KBAlert _markFinishedAndContinue];
}];
[ac addAction:cancelAct];
[ac addAction:okAct];
[vc presentViewController:ac animated:YES completion:nil];
}];
}
+ (void)promptTitle:(NSString *)title
message:(NSString *)message
placeholder:(NSString *)placeholder
ok:(NSString *)okTitle
cancel:(NSString *)cancelTitle
keyboardType:(UIKeyboardType)type
configuration:(void (^)(UITextField * _Nonnull))config
completion:(KBAlertTextHandler)completion {
[self enqueuePresent:^{
UIViewController *vc = [self presentingVC];
if (!vc) { [self _markFinishedAndContinue]; return; }
NSString *ok = okTitle ?: @"确定";
NSString *cancel = cancelTitle ?: @"取消";
UIAlertController *ac = [UIAlertController alertControllerWithTitle:(title ?: @"")
message:(message ?: @"")
preferredStyle:UIAlertControllerStyleAlert];
__weak UIAlertController *wac = ac;
[ac addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull tf) {
tf.placeholder = placeholder;
tf.keyboardType = type;
if (config) { config(tf); }
}];
UIAlertAction *cancelAct = [UIAlertAction actionWithTitle:cancel style:UIAlertActionStyleCancel handler:^(__unused UIAlertAction * _Nonnull a) {
if (completion) { completion(nil, NO); }
[wac dismissViewControllerAnimated:YES completion:nil];
[KBAlert _markFinishedAndContinue];
}];
UIAlertAction *okAct = [UIAlertAction actionWithTitle:ok style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction * _Nonnull a) {
NSString *text = wac.textFields.firstObject.text;
if (completion) { completion(text, YES); }
[wac dismissViewControllerAnimated:YES completion:nil];
[KBAlert _markFinishedAndContinue];
}];
[ac addAction:cancelAct];
[ac addAction:okAct];
[vc presentViewController:ac animated:YES completion:nil];
}];
}
+ (void)actionSheetTitle:(NSString *)title
message:(NSString *)message
actions:(NSArray<NSString *> *)actions
cancel:(NSString *)cancelTitle
destructiveIndex:(NSInteger)destructiveIndex
fromView:(UIView *)anchorView
completion:(KBAlertIndexHandler)completion {
[self enqueuePresent:^{
UIViewController *vc = [self presentingVC];
if (!vc) { [self _markFinishedAndContinue]; return; }
UIAlertController *ac = [UIAlertController alertControllerWithTitle:(title ?: @"")
message:(message ?: @"")
preferredStyle:UIAlertControllerStyleActionSheet];
__weak UIAlertController *wac = ac;
[actions enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
UIAlertActionStyle style = (destructiveIndex >= 0 && (NSInteger)idx == destructiveIndex) ? UIAlertActionStyleDestructive : UIAlertActionStyleDefault;
UIAlertAction *act = [UIAlertAction actionWithTitle:obj ?: @"" style:style handler:^(__unused UIAlertAction * _Nonnull a) {
if (completion) { completion((NSInteger)idx); }
[wac dismissViewControllerAnimated:YES completion:nil];
[KBAlert _markFinishedAndContinue];
}];
[ac addAction:act];
}];
if (cancelTitle.length) {
UIAlertAction *cancel = [UIAlertAction actionWithTitle:cancelTitle style:UIAlertActionStyleCancel handler:^(__unused UIAlertAction * _Nonnull a) {
if (completion) { completion(-1); }
[wac dismissViewControllerAnimated:YES completion:nil];
[KBAlert _markFinishedAndContinue];
}];
[ac addAction:cancel];
}
[self configurePopoverIfNeeded:ac anchorView:anchorView inVC:vc];
[vc presentViewController:ac animated:YES completion:nil];
}];
}
@end

View File

@@ -75,7 +75,7 @@
desc:d[@"desc"] desc:d[@"desc"]
people:d[@"people"] people:d[@"people"]
added:added]; added:added];
__weak typeof(self) weakSelf = self; KBWeakSelf
cell.onTapAction = ^{ cell.onTapAction = ^{
// / // /
NSMutableArray *m = [weakSelf.dataSource mutableCopy]; NSMutableArray *m = [weakSelf.dataSource mutableCopy];

View File

@@ -132,7 +132,7 @@
- (void)onContinue { - (void)onContinue {
LoginViewController *login = [LoginViewController new]; LoginViewController *login = [LoginViewController new];
__weak typeof(self) weakSelf = self; KBWeakSelf
login.onLoginSuccess = ^(NSDictionary * _Nonnull userInfo) { login.onLoginSuccess = ^(NSDictionary * _Nonnull userInfo) {
__strong typeof(weakSelf) self = weakSelf; if (!self) return; __strong typeof(weakSelf) self = weakSelf; if (!self) return;
[self dismissViewControllerAnimated:YES completion:^{ [self dismissViewControllerAnimated:YES completion:^{

View File

@@ -114,7 +114,7 @@
} }
- (void)handleAppleIDButtonPress API_AVAILABLE(ios(13.0)) { - (void)handleAppleIDButtonPress API_AVAILABLE(ios(13.0)) {
__weak typeof(self) weakSelf = self; KBWeakSelf
[[AppleSignInManager shared] signInFromViewController:self completion:^(ASAuthorizationAppleIDCredential * _Nullable credential, NSError * _Nullable error) { [[AppleSignInManager shared] signInFromViewController:self completion:^(ASAuthorizationAppleIDCredential * _Nullable credential, NSError * _Nullable error) {
__strong typeof(weakSelf) selfStrong = weakSelf; __strong typeof(weakSelf) selfStrong = weakSelf;
if (error) { if (error) {

View File

@@ -182,7 +182,7 @@ typedef NS_ENUM(NSInteger, KBSkinDetailSection) {
_bottomBar = [[KBSkinBottomActionView alloc] init]; _bottomBar = [[KBSkinBottomActionView alloc] init];
// / // /
[_bottomBar configWithTitle:@"Download" price:@"20" icon:nil]; [_bottomBar configWithTitle:@"Download" price:@"20" icon:nil];
__weak typeof(self) weakSelf = self; KBWeakSelf
_bottomBar.tapHandler = ^{ _bottomBar.tapHandler = ^{
// / // /
// [KBHUD showText:@"点击了下载"]; // [KBHUD showText:@"点击了下载"];

View File

@@ -55,7 +55,7 @@ static NSString * const kMySkinCellId = @"kMySkinCellId";
}]; }];
// LYEmptyView + // LYEmptyView +
__weak typeof(self) weakSelf = self; KBWeakSelf
[self.collectionView kb_makeDefaultEmptyViewWithImage:nil [self.collectionView kb_makeDefaultEmptyViewWithImage:nil
title:@"暂无皮肤" title:@"暂无皮肤"
detail:@"下拉刷新试试" detail:@"下拉刷新试试"

View File

@@ -152,7 +152,7 @@ static NSString * const kResultCellId = @"KBSkinCardCell";
if (!_searchBarView) { if (!_searchBarView) {
_searchBarView = [[KBSearchBarView alloc] init]; _searchBarView = [[KBSearchBarView alloc] init];
_searchBarView.placeholder = @"Themes"; _searchBarView.placeholder = @"Themes";
__weak typeof(self) weakSelf = self; KBWeakSelf
_searchBarView.onSearch = ^(NSString * _Nonnull keyword) { _searchBarView.onSearch = ^(NSString * _Nonnull keyword) {
[weakSelf performSearch:keyword]; [weakSelf performSearch:keyword];
}; };

View File

@@ -285,7 +285,7 @@ typedef NS_ENUM(NSInteger, KBSearchSection) {
if (indexPath.section == KBSearchSectionHistory) { if (indexPath.section == KBSearchSectionHistory) {
// sizeForHeader 0 // sizeForHeader 0
[header configWithTitle:@"Historical Search" showTrash:self.historyWords.count > 0]; [header configWithTitle:@"Historical Search" showTrash:self.historyWords.count > 0];
__weak typeof(self) weakSelf = self; KBWeakSelf
header.onTapTrash = ^{ [weakSelf clearHistory]; }; header.onTapTrash = ^{ [weakSelf clearHistory]; };
} else { } else {
[header configWithTitle:@"Recommended Skin" showTrash:NO]; [header configWithTitle:@"Recommended Skin" showTrash:NO];
@@ -363,7 +363,7 @@ typedef NS_ENUM(NSInteger, KBSearchSection) {
if (!_searchBarView) { if (!_searchBarView) {
_searchBarView = [[KBSearchBarView alloc] init]; _searchBarView = [[KBSearchBarView alloc] init];
_searchBarView.placeholder = @"Themes"; _searchBarView.placeholder = @"Themes";
__weak typeof(self) weakSelf = self; KBWeakSelf
_searchBarView.onSearch = ^(NSString * _Nonnull keyword) { _searchBarView.onSearch = ^(NSString * _Nonnull keyword) {
// + // +
[weakSelf performSearch:keyword]; [weakSelf performSearch:keyword];

View File

@@ -27,7 +27,7 @@
}]; }];
// 2 // 2
__weak typeof(self) weakSelf = self; KBWeakSelf
if (self.isNeedHeader) { if (self.isNeedHeader) {
self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

View File

@@ -21,6 +21,7 @@
/// 系统 /// 系统
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "KBHUD.h" #import "KBHUD.h"
#import "KBAlert.h"
#import "KBNetworkManager.h" #import "KBNetworkManager.h"