使用 self.delegate 子类化 UITextField 会导致应用程序冻结,CPU 峰值达到 100%
Posted
技术标签:
【中文标题】使用 self.delegate 子类化 UITextField 会导致应用程序冻结,CPU 峰值达到 100%【英文标题】:Subclassing UITextField with self.delegate causes app to freeze, CPU spikes to 100% 【发布时间】:2014-10-21 13:43:43 【问题描述】:我有一个UITextField
的子类,它设置self.delegate = self
。该子类用于防止将特殊字符输入UITextField
。起初它工作正常,但在按下几个键后,CPU 飙升至 100% 并冻结应用程序。 Xcode 中没有崩溃日志,因为该应用程序实际上从未崩溃,它只是保持冻结状态,直到我停止它。经过一番研究,我确定问题在于将delegate
设置为self
- 显然我应该为UITextField
创建一个单独的delegate
?我在网上搜索过,但找不到任何有用的方法。
我的 AcceptedCharacters 子类:
AcceptedCharacters.h
#import <UIKit/UIKit.h>
@interface AcceptedCharacters : UITextField <UITextFieldDelegate>
@end
和
AcceptedCharacters.m
#import "AcceptedCharacters.h"
#define ACCEPTABLE_CHARACTERS @" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_."
@implementation AcceptedCharacters
- (void)awakeFromNib
[super awakeFromNib];
if (self)
self.delegate = self;
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
//NSLog(@"AcceptedCharacters");
// Restrict special characters
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
return [string isEqualToString:filtered];
@end
我在堆栈溢出中发现的类似问题:
Application freezes after editing custom UITextField
UITextField delegate jumping to 100% CPU usage and crashing upon using keyboard shortcut
Why does UITextField lock up when setting itself to delegate
我已经阅读了解决方案,但对于初学者来说它们非常模糊。我将非常感谢有人在下面修改我的代码,甚至将我指向教程或文档的方向?提前致谢。
编辑:
我已经在我的ViewControllers
之一上测试了此代码,当符合UITextFieldDelegate
协议并且我的文本字段delegates
设置为self
时它工作正常(见下面的sn-p)。
在我的viewDidLoad
方法中:
self.forenameField.delegate = self;
self.surnameField.delegate = self;
self.addLine1Field.delegate = self;
self.addLine2Field.delegate = self;
self.addLine3Field.delegate = self;
self.addLine4Field.delegate = self;
self.addLine5Field.delegate = self;
self.postcodeField.delegate = self;
self.telLandField.delegate = self;
self.telMobField.delegate = self;
self.emailField.delegate = self;
self.dobField.delegate = self;
self.niNumField.delegate = self;
我宁愿创建UITextField
的几个子类并在特定的文本字段上调用它们,而不是像下面那样使用混乱的方法。
#define ACCEPTABLE_CHARACTERS @" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_."
#define NUMBERS_ONLY @"1234567890"
#define CHARACTER_LIMIT 11
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
// Restrict special characters
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
// Convert postcode field characters to uppercase
if (textField == self.postcodeField)
[textField setText:[textField.text stringByReplacingCharactersInRange:range withString:[string uppercaseString]]];
return NO;
// Set max character limit on tel fields
if (textField == self.telMobField || textField == self.telLandField)
NSUInteger newLength = [textField.text length] + [string length] - range.length;
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:NUMBERS_ONLY] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
return (([string isEqualToString:filtered])&&(newLength <= CHARACTER_LIMIT));
//return YES;
return [string isEqualToString:filtered];
【问题讨论】:
我认为这个答案应该可以很好地描述它:***.com/a/8049532/2708650 我对你的建议是永远不要以任何理由在任何课程上致电self.delegate = self
。拥有委托的原因是因为类本身无法处理状态。如果您将 self
指定为委托,则意味着您的类确实处理状态。
感谢您的链接,但我已阅读该帖子数次,仍然找不到解决方案。我可以将textField shouldChangeCharactersInRange:
方法添加到我的班级并在其中分配self.myTextField.delegate = self;
,它工作正常,尽管我的一些ViewController
s 有许多UITextFields
,它们都做不同的事情。与其有一个不整洁的textField shouldChangeCharactersInRange:
方法,不如在不同的文本字段上调用不同的子类更有效吗?请以我更新的帖子为例。
【参考方案1】:
试试这个:
@interface MyTextField : UITextField
- (BOOL)stringIsAcceptable:(NSString *)string inRange:(NSRange)range;
@end
@implementation MyTextField
- (BOOL)stringIsAcceptable:(NSString *)string inRange:(NSRange)range
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
return [string isEqualToString:filtered];
@end
@interface PostalCodeTextField : MyTextField
@end
@implementation PostalCodeTextField
- (BOOL)stringIsAcceptable:(NSString *)string inRange:(NSRange)range
[self setText:[self.text stringByReplacingCharactersInRange:range withString:[string uppercaseString]]];
return NO;
@end
.. more subclasses
然后将您的视图控制器分配为委托并在您的视图控制器中:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
if ([textField isKindOfClass:[MyTextField class]])
return [(MyTextField *)textField stringIsAcceptable:string inRange:range];
return YES;
【讨论】:
我对你的回答有点困惑,你的意思是把这段代码写在我的ViewController
类上,该类包含textfields
?我不想在实际的ViewController
类上调用textField delegate
方法,请参阅我更新的帖子,因为我已经这样做了,当有多个textfields
时,该方法最终变得混乱且难以调试做不同的事情。或者你的意思是用你的代码修改我的subclass
?抱歉,我还在学习子类和委托,谢谢。
不必那么乱。我会为你进一步扩展我的答案。
抱歉回复晚了,我刚刚实现了你的代码,它运行良好!这是一个比我使用的更优雅的解决方案,现在我可以根据需要创建尽可能多的子类,并在我的 ViewController
类的 shouldChangeCharactersInRange:
delegate
方法上调用它们。我真的很喜欢这个解决方案,非常感谢您花时间帮助我:)以上是关于使用 self.delegate 子类化 UITextField 会导致应用程序冻结,CPU 峰值达到 100%的主要内容,如果未能解决你的问题,请参考以下文章
“self.delegate = self”不能在使用 ARC 的 iOS 上运行
在 self.delegate 实现 UIAlertViewDelegate 协议的 alertView 中设置 delegate:self.delegate