Is it possible to detect that the user has an external headset plugged into the iPhone's 3.5mm connector or the 30-pin connector? I want to output audio only to an external audio device, and keep silent if nothing is connected.
The answer is very similar to the answer to this question, but you'll want to get the kAudioSessionProperty_AudioRoute property instead.
Call this method to find out the bluetooth headset is connected or not.
First import this framework #import <AVFoundation/AVFoundation.h>
- (BOOL) isBluetoothHeadsetConnected
{
AVAudioSession *session = [AVAudioSession sharedInstance];
AVAudioSessionRouteDescription *routeDescription = [session currentRoute];
NSLog(#"Current Routes : %#", routeDescription);
if (routeDescription)
{
NSArray *outputs = [routeDescription outputs];
if (outputs && [outputs count] > 0)
{
AVAudioSessionPortDescription *portDescription = [outputs objectAtIndex:0];
NSString *portType = [portDescription portType];
NSLog(#"dataSourceName : %#", portType);
if (portType && [portType isEqualToString:#"BluetoothA2DPOutput"])
{
return YES;
}
}
}
return NO;
}
There is nice article about this in Apple documentation:
https://developer.apple.com/documentation/avfoundation/avaudiosession/responding_to_audio_session_route_changes
Only you have to verify if portType == AVAudioSessionPortBluetoothA2DP
func setupNotifications() {
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self,
selector: #selector(handleRouteChange),
name: .AVAudioSessionRouteChange,
object: nil)
}
#objc func handleRouteChange(notification: Notification) {
guard let userInfo = notification.userInfo,
let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
let reason = AVAudioSessionRouteChangeReason(rawValue:reasonValue) else {
return
}
switch reason {
case .newDeviceAvailable:
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
headsetConnected = true
break
}
case .oldDeviceUnavailable:
if let previousRoute =
userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
for output in previousRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
headsetConnected = false
break
}
}
default: ()
}
}
func isBluetoothHeadsetConnected() -> Bool {
var result = false
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
result = true
}
return result
}
How can I put a default value into my string if getting data from an empty key/value in a dictionary.
so [myObject setMyString:[dictionary valueForKey:#"myKey"]];
So then if I did NSString *newString = myObject.myString I would get an unrecognized selector error.
So again, I simply need a way to insert a default string if the key value is empty;
If dictionary is a NSDictionary you should probably use objectForKey as valueForKey is used for KVC. It works for NSDictionary but may bite you if the key collide with some NSDictionary KVC key, e.g. "#allKeys" or "#count".
I think the shortest is probably to do:
[dictionary objectForkey:#"myKey"] ?: #"defaultValue"
There is one terrible way of abusing the existing dictionary methods to produce a get by key or return a default value if you don't want to use a condition for some reason...
[[dictionary objectsForKeys:[NSArray arrayWithObject:#"myKey"]
notFoundMarker:#"defaultValue"]
objectAtIndex:0]
You did not hear it from me :)
What about this?
NSString *value = [dictionary valueForKey:#"myKey"];
if (!value) value = #"defaultValue";
[myObject setMyString:value];
Use [NSNull null] for the general case, and handle it when that is returned.
In your question, you wouldn't get "unrecognised selector"; newString would be set to nil (as opposed to [NSNull null], so I suspect you might have meant something else - perhaps how to set defaults values for NSUserDefaults?
I've done this with a simple NSDictionary extension.
NSDictionary+NSDictionaryExtensions.h
#import <Foundation/Foundation.h>
#interface NSDictionary (NSDictionaryExtensions)
- (id)objectForKey:(id)aKey defaultObject: (id) defObj;
#end
NSDictionary+NSDictionaryExtensions.m
#import "NSDictionary+NSDictionaryExtensions.h"
#implementation NSDictionary (NSDictionaryExtensions)
- (id)objectForKey:(id)aKey defaultObject: (id) defObj
{
id ret = [self objectForKey: aKey];
if ( ret == nil )
return defObj;
else
return ret;
}
#end
I can then access as follows:
NSString* str = [dict objectForKey: #"a_key" defaultObject: #"default"];
try
if ( myObject == nil ) {
[myObject setMyString:#""];
}
or
if ( [dictionary valueForKey:#"myKey"] == nil ) {
[dictionary setObject:#"" forKey:#"myKey"];
}
Whatever default value you assigned to your string it will not make myObject.myString return "unrecognized selector error" - usually the property myString either exists or it does not ('usually' as you can dig into the guts of the Objective-C runtime and play games, but this is rarely (if ever) what you want to do!)
What are you trying to do? If your aim is to throw an exception on myObject.myString not being set then you can do that in the property implementation.
For example, valueForKey; will return nil if there is no value set for a given key, so you can check for that in your property:
- (void) setMyString:(NSString *)value
{ myString = value;
}
- (NSString *) myString
{
if (myString == nil)
#throw [NSException exceptionWithName:#"UnrecognizedSelector" reason:#"No value set for myString" userInfo:nil];
return myString;
}
Notes:
code typed at terminal, may contain typos
code assumes garbage collection/ARC on, if not you need to add appropriate retain/copy/release
But do you really want to throw an exception? You would normally only do so if the string should be set and not being so is an exceptional condition - you don't throw for default values.
As per #Paul Lynch you must check for [NSNull null] apart from nil. It is also advisable to check for the data type you are looking for:
- (id) objectForKey: (id) key withDefault: (id) defaultValue
{
id value = self[key];
if (value == nil || [value isEqual: [NSNull null]] || ![defaultValue isKindOfClass: [value class]])
{
value = defaultValue;
}
return value;
}
You can manually check for nil values as below for different types:
extension NSDictionary {
func convertToString() -> String {
let jsonData = try! JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions.prettyPrinted) as NSData!
if jsonData == nil{
return "{}"
}else {
return String(data: jsonData as! Data, encoding: String.Encoding.utf8)!
}
}
func object_forKeyWithValidationForClass_Int(aKey: String) -> Int {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return Int()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return Int()
}
} else {
// KEY NOT FOUND
return Int()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return Int()
}
else if(aValue.isKind(of: NSString.self)){
return Int((aValue as! NSString).intValue)
}
else {
if aValue is Int {
return self.object(forKey: aKey) as! Int
}
else{
return Int()
}
}
}
func object_forKeyWithValidationForClass_CGFloat(aKey: String) -> CGFloat {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return CGFloat()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return CGFloat()
}
} else {
// KEY NOT FOUND
return CGFloat()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return CGFloat()
}
else {
if aValue is CGFloat {
return self.object(forKey: aKey) as! CGFloat
}
else{
return CGFloat()
}
}
}
func object_forKeyWithValidationForClass_String(aKey: String) -> String {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return String()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return String()
}
} else {
// KEY NOT FOUND
return String()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return String()
}
else if(aValue.isKind(of: NSNumber.self)){
return String(format:"%f", (aValue as! NSNumber).doubleValue)
}
else {
if aValue is String {
return self.object(forKey: aKey) as! String
}
else{
return String()
}
}
}
func object_forKeyWithValidationForClass_StringInt(aKey: String) -> String {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return String()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return String()
}
} else {
// KEY NOT FOUND
return String()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return String()
}
else if(aValue.isKind(of: NSNumber.self)){
return String(format:"%d", (aValue as! NSNumber).int64Value)
}
else {
if aValue is String {
return self.object(forKey: aKey) as! String
}
else{
return String()
}
}
}
func object_forKeyWithValidationForClass_Bool(aKey: String) -> Bool {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return Bool()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return Bool()
}
} else {
// KEY NOT FOUND
return Bool()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return Bool()
}
else {
if aValue is Bool {
return self.object(forKey: aKey) as! Bool
}
else{
return Bool()
}
}
}
func object_forKeyWithValidationForClass_NSArray(aKey: String) -> NSArray {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSArray()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSArray()
}
} else {
// KEY NOT FOUND
return NSArray()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSArray()
}
else {
if aValue is NSArray {
return self.object(forKey: aKey) as! NSArray
}
else{
return NSArray()
}
}
}
func object_forKeyWithValidationForClass_NSMutableArray(aKey: String) -> NSMutableArray {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSMutableArray()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSMutableArray()
}
} else {
// KEY NOT FOUND
return NSMutableArray()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSMutableArray()
}
else {
if aValue is NSMutableArray {
return self.object(forKey: aKey) as! NSMutableArray
}
else{
return NSMutableArray()
}
}
}
func object_forKeyWithValidationForClass_NSDictionary(aKey: String) -> NSDictionary {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSDictionary()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSDictionary()
}
} else {
// KEY NOT FOUND
return NSDictionary()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSDictionary()
}
else {
if aValue is NSDictionary {
return self.object(forKey: aKey) as! NSDictionary
}
else{
return NSDictionary()
}
}
}
func object_forKeyWithValidationForClass_NSMutableDictionary(aKey: String) -> NSMutableDictionary {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSMutableDictionary()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSMutableDictionary()
}
} else {
// KEY NOT FOUND
return NSMutableDictionary()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSMutableDictionary()
}
else {
if aValue is NSMutableDictionary {
return self.object(forKey: aKey) as! NSMutableDictionary
}
else{
return NSMutableDictionary()
}
}
}
}
In an iPhone app I am developing, there is a setting in which you can enter a URL, because of form & function this URL needs to be validated online as well as offline.
So far I haven't been able to find any method to validate the url, so the question is;
How do I validate an URL input on the iPhone (Objective-C) online as well as offline?
Why not instead simply rely on Foundation.framework?
That does the job and does not require RegexKit :
NSURL *candidateURL = [NSURL URLWithString:candidate];
// WARNING > "test" is an URL according to RFCs, being just a path
// so you still should check scheme and all other NSURL attributes you need
if (candidateURL && candidateURL.scheme && candidateURL.host) {
// candidate is a well-formed url with:
// - a scheme (like http://)
// - a host (like stackoverflow.com)
}
According to Apple documentation :
URLWithString: Creates and returns an NSURL object initialized with a
provided string.
+ (id)URLWithString:(NSString *)URLString
Parameters
URLString : The string with which to initialize the NSURL object. Must conform to RFC 2396. This method parses URLString according to RFCs 1738 and 1808.
Return Value
An NSURL object initialized with URLString. If the string was malformed, returns nil.
Thanks to this post, you can avoid using RegexKit.
Here is my solution (works for iphone development with iOS > 3.0) :
- (BOOL) validateUrl: (NSString *) candidate {
NSString *urlRegEx =
#"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+";
NSPredicate *urlTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", urlRegEx];
return [urlTest evaluateWithObject:candidate];
}
If you want to check in Swift my solution given below:
func isValidUrl(url: String) -> Bool {
let urlRegEx = "^(https?://)?(www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6}(/[-\\w#\\+\\.~#\\?&/=%]*)?$"
let urlTest = NSPredicate(format:"SELF MATCHES %#", urlRegEx)
let result = urlTest.evaluate(with: url)
return result
}
Instead of writing your own regular expressions, rely on Apple's. I have been using a category on NSString that uses NSDataDetector to test for the presence of a link within a string. If the range of the link found by NSDataDetector equals the length of the entire string, then it is a valid URL.
- (BOOL)isValidURL {
NSUInteger length = [self length];
// Empty strings should return NO
if (length > 0) {
NSError *error = nil;
NSDataDetector *dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];
if (dataDetector && !error) {
NSRange range = NSMakeRange(0, length);
NSRange notFoundRange = (NSRange){NSNotFound, 0};
NSRange linkRange = [dataDetector rangeOfFirstMatchInString:self options:0 range:range];
if (!NSEqualRanges(notFoundRange, linkRange) && NSEqualRanges(range, linkRange)) {
return YES;
}
}
else {
NSLog(#"Could not create link data detector: %# %#", [error localizedDescription], [error userInfo]);
}
}
return NO;
}
My solution with Swift:
func validateUrl (stringURL : NSString) -> Bool {
var urlRegEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
let predicate = NSPredicate(format:"SELF MATCHES %#", argumentArray:[urlRegEx])
var urlTest = NSPredicate.predicateWithSubstitutionVariables(predicate)
return predicate.evaluateWithObject(stringURL)
}
For Test:
var boolean1 = validateUrl("http.s://www.gmail.com")
var boolean2 = validateUrl("https:.//gmailcom")
var boolean3 = validateUrl("https://gmail.me.")
var boolean4 = validateUrl("https://www.gmail.me.com.com.com.com")
var boolean6 = validateUrl("http:/./ww-w.wowone.com")
var boolean7 = validateUrl("http://.www.wowone")
var boolean8 = validateUrl("http://www.wow-one.com")
var boolean9 = validateUrl("http://www.wow_one.com")
var boolean10 = validateUrl("http://.")
var boolean11 = validateUrl("http://")
var boolean12 = validateUrl("http://k")
Results:
false
false
false
true
false
false
true
true
false
false
false
use this-
NSString *urlRegEx = #"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?";
I solved the problem using RegexKit, and build a quick regex to validate a URL;
NSString *regexString = #"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+";
NSString *subjectString = brandLink.text;
NSString *matchedString = [subjectString stringByMatching:regexString];
Then I check if the matchedString is equal to the subjectString and if that is the case the url is valid :)
Correct me if my regex is wrong ;)
I've found the easiest way to do this is like so:
- (BOOL)validateUrl: (NSURL *)candidate
{
NSURLRequest *req = [NSURLRequest requestWithURL:candidate];
return [NSURLConnection canHandleRequest:req];
}
Oddly enough, I didn't really find a solution here that was very simple, yet still did an okay job for handling http / https links.
Keep in mind, THIS IS NOT a perfect solution, but it worked for the cases below. In summary, the regex tests whether the URL starts with http:// or https://, then checks for at least 1 character, then checks for a dot, and then again checks for at least 1 character. No spaces allowed.
+ (BOOL)validateLink:(NSString *)link
{
NSString *regex = #"(?i)(http|https)(:\\/\\/)([^ .]+)(\\.)([^ \n]+)";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
return [predicate evaluateWithObject:link];
}
Tested VALID against these URLs:
#"HTTP://FOO.COM",
#"HTTPS://FOO.COM",
#"http://foo.com/blah_blah",
#"http://foo.com/blah_blah/",
#"http://foo.com/blah_blah_(wikipedia)",
#"http://foo.com/blah_blah_(wikipedia)_(again)",
#"http://www.example.com/wpstyle/?p=364",
#"https://www.example.com/foo/?bar=baz&inga=42&quux",
#"http://✪df.ws/123",
#"http://userid:password#example.com:8080",
#"http://userid:password#example.com:8080/",
#"http://userid#example.com",
#"http://userid#example.com/",
#"http://userid#example.com:8080",
#"http://userid#example.com:8080/",
#"http://userid:password#example.com",
#"http://userid:password#example.com/",
#"http://142.42.1.1/",
#"http://142.42.1.1:8080/",
#"http://➡.ws/䨹",
#"http://⌘.ws",
#"http://⌘.ws/",
#"http://foo.com/blah_(wikipedia)#cite-",
#"http://foo.com/blah_(wikipedia)_blah#cite-",
#"http://foo.com/unicode_(✪)_in_parens",
#"http://foo.com/(something)?after=parens",
#"http://☺.damowmow.com/",
#"http://code.google.com/events/#&product=browser",
#"http://j.mp",
#"http://foo.bar/?q=Test%20URL-encoded%20stuff",
#"http://مثال.إختبار",
#"http://例子.测试",
#"http://उदाहरण.परीक्षा",
#"http://-.~_!$&'()*+,;=:%40:80%2f::::::#example.com",
#"http://1337.net",
#"http://a.b-c.de",
#"http://223.255.255.254"
Tested INVALID against these URLs:
#"",
#"foo",
#"ftp://foo.com",
#"ftp://foo.com",
#"http://..",
#"http://..",
#"http://../",
#"//",
#"///",
#"http://##/",
#"http://.www.foo.bar./",
#"rdar://1234",
#"http://foo.bar?q=Spaces should be encoded",
#"http:// shouldfail.com",
#":// should fail"
Source of URLs:
https://mathiasbynens.be/demo/url-regex
You can use this if you do not want http or https or www
NSString *urlRegEx = #"^(http(s)?://)?((www)?\.)?[\w]+\.[\w]+";
example
- (void) testUrl:(NSString *)urlString{
NSLog(#"%#: %#", ([self isValidUrl:urlString] ? #"VALID" : #"INVALID"), urlString);
}
- (void)doTestUrls{
[self testUrl:#"google"];
[self testUrl:#"google.de"];
[self testUrl:#"www.google.de"];
[self testUrl:#"http://www.google.de"];
[self testUrl:#"http://google.de"];
}
Output:
INVALID: google
VALID: google.de
VALID: www.google.de
VALID: http://www.google.de
VALID: http://google.de
Lefakir's solution has one issue.
His regex can't match with "http://instagram.com/p/4Mz3dTJ-ra/".
Url component has combined numerical and literal character. His regex fail such urls.
Here is my improvement.
"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*)+)+(/)?(\\?.*)?"
Below code will let you find the valid URLs
NSPredicate *websitePredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",#"^(((((h|H)(t|T){2}(p|P)s?)|((f|F)(t|T)(p|P)))://(w{3}.)?)|(w{3}.))[A-Za-z0-9]+(.[A-Za-z0-9-:;\?#_]+)+"];
if ([websitePredicate evaluateWithObject:##MY_STRING##])
{
printf"Valid"
}
for such URLS
http://123.com
https://123.com
http://www.123.com
https://www.123.com
ftp://123.com
ftp://www.123.com
www.something.com
The approved answer is incorrect.
I have an URL with an "-" in it, and the validation fails.
Tweeked Vaibhav's answer to support G+ links:
NSString *urlRegEx = #"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-\\+ ./?%&=]*)?";
Some URL's without / at the end are not detected as the correct one in the solutions above. So this might be helpful.
extension String {
func isValidURL() -> Bool{
let length:Int = self.characters.count
var err:NSError?
var dataDetector:NSDataDetector? = NSDataDetector()
do{
dataDetector = try NSDataDetector(types: NSTextCheckingType.Link.rawValue)
}catch{
err = error as NSError
}
if dataDetector != nil{
let range = NSMakeRange(0, length)
let notFoundRange = NSRange(location: NSNotFound, length: 0)
let linkRange = dataDetector?.rangeOfFirstMatchInString(self, options: NSMatchingOptions.init(rawValue: 0), range: range)
if !NSEqualRanges(notFoundRange, linkRange!) && NSEqualRanges(range, linkRange!){
return true
}
}else{
print("Could not create link data detector: \(err?.localizedDescription): \(err?.userInfo)")
}
return false
}
}
URL Validation in Swift
Details
Xcode 8.2.1, Swift 3
Code
enum URLSchemes: String
import Foundation
enum URLSchemes: String {
case http = "http://", https = "https://", ftp = "ftp://", unknown = "unknown://"
static func detectScheme(urlString: String) -> URLSchemes {
if URLSchemes.isSchemeCorrect(urlString: urlString, scheme: .http) {
return .http
}
if URLSchemes.isSchemeCorrect(urlString: urlString, scheme: .https) {
return .https
}
if URLSchemes.isSchemeCorrect(urlString: urlString, scheme: .ftp) {
return .ftp
}
return .unknown
}
static func getAllSchemes(separetedBy separator: String) -> String {
return "\(URLSchemes.http.rawValue)\(separator)\(URLSchemes.https.rawValue)\(separator)\(URLSchemes.ftp.rawValue)"
}
private static func isSchemeCorrect(urlString: String, scheme: URLSchemes) -> Bool {
if urlString.replacingOccurrences(of: scheme.rawValue, with: "") == urlString {
return false
}
return true
}
}
extension String
import Foundation
extension String {
var isUrl: Bool {
// for http://regexr.com checking
// (?:(?:https?|ftp):\/\/)(?:xn--)?(?:\S+(?::\S*)?#)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[#-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?
let schemes = URLSchemes.getAllSchemes(separetedBy: "|").replacingOccurrences(of: "://", with: "")
let regex = "(?:(?:\(schemes)):\\/\\/)(?:xn--)?(?:\\S+(?::\\S*)?#)?(?:(?!10(?:\\.\\d{1,3}){3})(?!127(?:\\.\\d{1,3}){3})(?!169\\.254(?:\\.\\d{1,3}){2})(?!192\\.168(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[#-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:\\/[^\\s]*)?"
let regularExpression = try! NSRegularExpression(pattern: regex, options: [])
let range = NSRange(location: 0, length: self.characters.count)
let matches = regularExpression.matches(in: self, options: [], range: range)
for match in matches {
if range.location == match.range.location && range.length == match.range.length {
return true
}
}
return false
}
var toURL: URL? {
let urlChecker: (String)->(URL?) = { url_string in
if url_string.isUrl, let url = URL(string: url_string) {
return url
}
return nil
}
if !contains(".") {
return nil
}
if let url = urlChecker(self) {
return url
}
let scheme = URLSchemes.detectScheme(urlString: self)
if scheme == .unknown {
let newEncodedString = URLSchemes.http.rawValue + self
if let url = urlChecker(newEncodedString) {
return url
}
}
return nil
}
}
Usage
func tests() {
chekUrl(urlString:"http://example.com")
chekUrl(urlString:"https://example.com")
chekUrl(urlString:"http://example.com/dir/file.php?var=moo")
chekUrl(urlString:"http://xn--h1aehhjhg.xn--d1acj3b")
chekUrl(urlString:"http://www.example.com/wpstyle/?p=364")
chekUrl(urlString:"http://-.~_!$&'()*+,;=:%40:80%2f::::::#example.com")
chekUrl(urlString:"http://example.com")
chekUrl(urlString:"http://xn--d1acpjx3f.xn--p1ai")
chekUrl(urlString:"http://xn--74h.damowmow.com/")
chekUrl(urlString:"ftp://example.com:129/myfiles")
chekUrl(urlString:"ftp://user:pass#site.com:21/file/dir")
chekUrl(urlString:"ftp://ftp.example.com:2828/asdah%20asdah.gif")
chekUrl(urlString:"http://142.42.1.1:8080/")
chekUrl(urlString:"http://142.42.1.1/")
chekUrl(urlString:"http://userid:password#example.com:8080")
chekUrl(urlString:"http://userid#example.com")
chekUrl(urlString:"http://userid#example.com:8080")
chekUrl(urlString:"http://foo.com/blah_(wikipedia)#cite-1")
chekUrl(urlString:"http://foo.com/(something)?after=parens")
print("\n----------------------------------------------\n")
chekUrl(urlString:".")
chekUrl(urlString:" ")
chekUrl(urlString:"")
chekUrl(urlString:"-/:;()₽&#.,?!'{}[];'<>+_)(*#^%$")
chekUrl(urlString:"localhost")
chekUrl(urlString:"yandex.")
chekUrl(urlString:"коряга")
chekUrl(urlString:"http:///a")
chekUrl(urlString:"ftps://foo.bar/")
chekUrl(urlString:"rdar://1234")
chekUrl(urlString:"h://test")
chekUrl(urlString:":// should fail")
chekUrl(urlString:"http://-error-.invalid/")
chekUrl(urlString:"http://.www.example.com/")
}
func chekUrl(urlString: String) {
var result = ""
if urlString.isUrl {
result += "url: "
} else {
result += "not url: "
}
result += "\"\(urlString)\""
print(result)
}
Result
Objective C
- (BOOL)validateUrlString:(NSString*)urlString
{
if (!urlString)
{
return NO;
}
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSRange urlStringRange = NSMakeRange(0, [urlString length]);
NSMatchingOptions matchingOptions = 0;
if (1 != [linkDetector numberOfMatchesInString:urlString options:matchingOptions range:urlStringRange])
{
return NO;
}
NSTextCheckingResult *checkingResult = [linkDetector firstMatchInString:urlString options:matchingOptions range:urlStringRange];
return checkingResult.resultType == NSTextCheckingTypeLink && NSEqualRanges(checkingResult.range, urlStringRange);
}
Hope this helps!
did you mean to check if what the user entered is a URL? It can be as simple as a regular expression, for example checking if the string contain www. (this is the way that yahoo messenger checks if the user status is a link or not)
Hope that help
Selfishly, I would suggest using a KSURLFormatter instance to both validate input, and convert it to something NSURL can handle.
I have created inherited class of UITextField which can handle all kind of validation using regex string. In this you just need to give them all the regex string in sequence and their message that you want to show when validation get failed. You can check my blog for more info, it will really help you
http://dhawaldawar.wordpress.com/2014/06/11/uitextfield-validation-ios/
Extending #Anthony's answer to swift, I wrote a category on String which returns an optional NSURL. The return value is nil if the String can not be validated to be a URL.
import Foundation
// A private global detector variable which can be reused.
private let detector = try! NSDataDetector(types: NSTextCheckingType.Link.rawValue)
extension String {
func URL() -> NSURL? {
let textRange = NSMakeRange(0, self.characters.count)
guard let URLResult = detector.firstMatchInString(self, options: [], range: textRange) else {
return nil
}
// This checks that the whole string is the detected URL. In case
// you don't have such a requirement, you can remove this code
// and return the URL from URLResult.
guard NSEqualRanges(URLResult.range, textRange) else {
return nil
}
return NSURL(string: self)
}
}
func checkValidUrl(_ strUrl: String) -> Bool {
let urlRegEx: String = "(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"
let urlTest = NSPredicate(format: "SELF MATCHES %#", urlRegEx)
return urlTest.evaluate(with: strUrl)
}
My solution in Swift 5:
extension String {
func isValidUrl() -> Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
// check if the string has link inside
return detector.numberOfMatches(in: self, options: [], range: .init( location: 0, length: utf16.count)) > 0
} catch {
print("Error during NSDatadetector initialization \(error)" )
}
return false
}
}
Is it possible to detect that the user has an external headset plugged into the iPhone's 3.5mm connector or the 30-pin connector? I want to output audio only to an external audio device, and keep silent if nothing is connected.
The answer is very similar to the answer to this question, but you'll want to get the kAudioSessionProperty_AudioRoute property instead.
Call this method to find out the bluetooth headset is connected or not.
First import this framework #import <AVFoundation/AVFoundation.h>
- (BOOL) isBluetoothHeadsetConnected
{
AVAudioSession *session = [AVAudioSession sharedInstance];
AVAudioSessionRouteDescription *routeDescription = [session currentRoute];
NSLog(#"Current Routes : %#", routeDescription);
if (routeDescription)
{
NSArray *outputs = [routeDescription outputs];
if (outputs && [outputs count] > 0)
{
AVAudioSessionPortDescription *portDescription = [outputs objectAtIndex:0];
NSString *portType = [portDescription portType];
NSLog(#"dataSourceName : %#", portType);
if (portType && [portType isEqualToString:#"BluetoothA2DPOutput"])
{
return YES;
}
}
}
return NO;
}
There is nice article about this in Apple documentation:
https://developer.apple.com/documentation/avfoundation/avaudiosession/responding_to_audio_session_route_changes
Only you have to verify if portType == AVAudioSessionPortBluetoothA2DP
func setupNotifications() {
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self,
selector: #selector(handleRouteChange),
name: .AVAudioSessionRouteChange,
object: nil)
}
#objc func handleRouteChange(notification: Notification) {
guard let userInfo = notification.userInfo,
let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
let reason = AVAudioSessionRouteChangeReason(rawValue:reasonValue) else {
return
}
switch reason {
case .newDeviceAvailable:
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
headsetConnected = true
break
}
case .oldDeviceUnavailable:
if let previousRoute =
userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
for output in previousRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
headsetConnected = false
break
}
}
default: ()
}
}
func isBluetoothHeadsetConnected() -> Bool {
var result = false
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
result = true
}
return result
}