当我的用户点击一个按钮,我希望应用程序提示用户打电话。我试图用下面的方法来完成这个任务,但是只要点击按钮,应用程序就会崩溃。我已经双重检查了NSString是否也在phoneUrl中填充(没有空值)。知道为什么会发生这种事吗?
*由于“NSInvalidArgumentException”异常终止应用程序,原因:'-NSURL长度:发送到实例0x280244620‘的未识别选择器,终止时类型为NSException。
ViewController.m
- (IBAction)phoneLocation:(id)sender {
NSString *number = self.locationHours.text;
NSString *noDashes = [number
stringByReplacingOccurrencesOfString:@"-" withString:@""];
NSURL *phoneUrl = [NSURL URLWithString:[NSString stringWithFormat:@"tel://%@", noDashes]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneUrl]];
}发布于 2020-11-29 07:06:19
我很惊讶居然会编译。非常肯定,您可能在最后一行中有警告:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneUrl]];您的phoneUrl在此调用之前被定义为NSURL *,但您将它作为NSString *参数传递。您可以通过Apple https://developer.apple.com/documentation/foundation/nsurl/1572047-urlwithstring验证这一点。
因此,在(instancetype)URLWithString:(NSString *)URLString;内部,调用(由于其内部实现细节)试图发送length Objective运行时消息(即从高级角度调用length方法),这对于NSString *完全有效,但对NSURL *绝对无效。因此,您可以看到您提供的NSInvalidArgumentException消息。
可能的修复方法可能是将最后一行更改为:
[[UIApplication sharedApplication] openURL:phoneUrl];更好的是,正如@OlSen所建议的那样,使用现代的非反对API:https://stackoverflow.com/a/48618644/1443038
发布于 2020-11-29 09:04:21
这个答案基本上建立在Kamil.S的原则之上,但使用现代API,如果拼写错误,它根本不会打开phoneUrl,它还可以防止在电话号码中使用双输入+符号。
在研究如何正确地打电话的同时,只发现容易出错的电话号码检测也试图在没有第三方依赖的情况下做出更好的检测。(请注意,下面的解决方案并不意味着要扫描全文,可能会有很多数字分散在单词之间) PS:是的,当数字排序合理时,您甚至可以将一个电话号码隐藏在更大的字符串中。假设您有一个包含..。
@"uglyPreString +49(17)-12-+345-678 uglyPostString seePlusInBetween?"或@"tel://+49(17)-12-+345-678"
它能用吗?决定在发送电话号码以调用其他应用程序(即手机应用程序)之前,编写一个确保您有一个正确的可拨号号码的程序。
NSString *dirty = @"uglyPreString +49(017)-12-+345-678 uglyPostString seePlusInBetween?";
// Let's keep all (only) possible phone number parts with a regex.
dirty = [dirty stringByReplacingOccurrencesOfString:@"[^0-9,^+]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, dirty.length)];
// We may have doublet '+' sign in there
// ending up in a wrong call, prevent that
if (dirty.length>1) {
// If the possible string contains '+' twice, kick out all '+' after first.
// If there was no + sign at all, string stays as is. And
// do not exceed max character index = NSMakeRange(1, dirty.length-1)
dirty = [dirty stringByReplacingOccurrencesOfString:@"[+]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(1, dirty.length-1)];
NSLog(@"does it look nice here? phone: %@",dirty);
}
// make sure it will not validate if detector doesnt agree its a phonenumber
// we don't want phonenumbers to fly as url call between app without users consent
// only apps that conform to handle @"tel://" protocol should be able to handle your call.
// so we set phonenumber invalid first.
NSString *phonenumber = nil;
NSError *error = nil;
NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber error:&error];
NSArray *check = [detector matchesInString:dirty options:0 range:NSMakeRange(0, dirty.length)];
if (check) {
for (NSTextCheckingResult *result in check) {
phonenumber = [result phoneNumber];
if (phonenumber) break;
}
// if this part is reached, there is no valid phonenumber in dirty
}
if (phonenumber) {
// construct the phone url
NSString *dial = [NSString stringWithFormat:@"tel://%@",phonenumber];
NSURL *phoneUrl = [NSURL URLWithString:dial];
NSLog(@"dial will be %@",phoneUrl.absoluteString);
if ([UIApplication.sharedApplication canOpenURL:phoneUrl]) {
[UIApplication.sharedApplication openURL:phoneUrl options:@{} completionHandler:^(BOOL success) {
// assuming the app that opens is phone app.
NSLog(@"pressed %@ button", success ? @"green/call" : @"red/cancel");
}];
}
}https://stackoverflow.com/questions/65057734
复制相似问题