Unable to find sigtrap exception - ios

I have submitted my app for review, but apple team regularly rejecting my app and telling they are getting exception. but i have tried it in multiple device and i am not getting any exception. they are telling they are getting exception while entering otp. i have given crash report provided by apple team below.
func validateOTP() -> Void {
var strOTP = String(format: "%#%#%#%#", txtFieldFirst.text ?? "1",txtFieldSecond.text ?? "0",txtFieldThird.text ?? "1",txtFieldFourth.text ?? "0")
strOTP = strOTP.trimmingCharacters(in: .whitespaces)
print("OTP:",strOTP)
if strOTP.count == 4 {
if isServerReachable() {
var dict: [String : Any] = [:]
dict["mobile"] = Defaults().strUserMobileNumber
dict["otp"] = strOTP
dict["device_id"] = StringConstant.Device.Id
dict["registration_id"] = Defaults().strDeviceToken
dict["device_type"] = StringConstant.Device.DeviceType
SVProgressHUD.show()
if strLoginType == StringConstant.kUserTypeStudent {
CCAParserLayer.callStudentLogin(dict, handler: { strStatus, strMessage, dictResponse in
SVProgressHUD.dismiss()
if (strStatus == "YES") {
let json = JSON(dictResponse!)
Defaults().strUserType = StringConstant.kUserTypeStudent
Defaults().strStudentId = json["student_data"][0]["student_id"].stringValue
Defaults().strUserId = json["student_data"][0]["user_id"].stringValue
Defaults().strStudentName = json["student_data"][0]["student_name"].stringValue
Defaults().strStudentMobile = json["student_data"][0]["student_mobile"].stringValue
Defaults().isLoggedIn = true
self.performSegue(withIdentifier: "otpToStudentDashboard", sender: self)
}else{
self.showToastAlert(strMessage ?? StringConstant.kErrorMsg)
}
})
}else{
CCAParserLayer.callCoachLogin(dict, handler: { strStatus, strMessage, dictResponse in
SVProgressHUD.dismiss()
if (strStatus == "YES") {
let json = JSON(dictResponse!)
Defaults().strUserType = StringConstant.kUserTypeCoach
Defaults().strUserId = json["user_id"].stringValue
Defaults().isLoggedIn = true
self.performSegue(withIdentifier: "otpToCoachDashboard", sender: self)
}else{
self.showToastAlert(strMessage ?? StringConstant.kErrorMsg)
}
})
}
}else{
showToastAlert(StringConstant.kNoInternet)
}
}
}
You can find crash report here : https://iosapps-ssl.itunes.apple.com/itunes-assets/Purple123/v4/c8/b4/f4/c8b4f459-268d-9e4f-41dc-e1a1debd59eb/attachment-14470021504513854757crashlog-F30F5C6F-07C9-4CC4-8B64-F59D82FB8BE3.txt?accessKey=1589094390_3573176945688459523_oOvkQoPlbl9fPoJG1v1vK5NdJTucUtWucC9bizZwY9B4EZuopjhvtKxf1naNx4BtYBPHmq2Ea0IfZs6uAOK65demdPuIBJvsxNIPFfrYYRhSRFT8ltCRFGBdHI5M8WWPyiCP4eRCwPkGaVVgFFVibbGEpYk4eDyInD0EiVNTfc8rDwSroUxEhY%2BdhrzluHhCVRkaPC5aMqSVFmY%2BMvW9SyvdvqS3dYOCEUb509YanCazpFPm%2FXSgxoTQFlNvzOnY

Related

How to get NWEndPoint from device

I am using NWListener, NWBrowser, and NWConnection for a local peer-to-peer discovery app. Because the vc with both the browser and listener initializes them both, I end up connecting with myself. The only way that I could think of to prevent that is to stop execution with a return statement if the connection.endPoint is equal to the device's endPoint eg.
listener?.newConnectionHandler = { (nwConnection) in
if nwConnection.endpoint == self.deviceEndpoint { return }
}
browser?.browseResultsChangedHandler = { (results, changes) in
for result in results {
if result.endpoint == self.deviceEndpoint { return }
}
}
How can I get the device's NWEndPoint?
vc:
var browser: PeerBrowser?
var listener: PeerListener?
override func viewDidLoad() {
super.viewDidLoad()
listener = PeerListener()
browser = PeerBrowser()
}
Listener:
class PeerListener {
var listener: NWListener?
var deviceEndpoint: NWEndPoint?
init() {
self.deviceEndpoint = ???
let tcpOptions = NWProtocolTCP.Options()
// ...
let params = NWParameters(tls: nil, tcp: tcpOptions)
params.includePeerToPeer = true
listener = try? NWListener(using: params)
listener?.service = NWListener.Service(name: "MyName", type: "_myApp._tcp")
listener?.stateUpdateHandler = { (newState) in ... }
listener?.newConnectionHandler = { (nwConnection) in
if nwConnection.endpoint == self.deviceEndpoint { return } // *** STOP EXECUTION HERE ***
// ...
}
}
}
Browser:
class PeerBrowser {
var browser: NWBrowser?
var deviceEndpoint: NWEndPoint?
init() {
self.deviceEndpoint = ???
let params = NWParameters()
params.includePeerToPeer = true
browser = NWBrowser(for: .bonjour(type: "_myApp_.tcp", domain: "local"), using: params)
browser?.stateUpdateHandler = { (newState) in ... }
browser?.browseResultsChangedHandler = { (results, changes) in
for result in results {
if result.endpoint == self.deviceEndpoint { return } // *** STOP EXECUTION HERE ***
// ...
}
}
}
}
The way i fixed this was to include a unique uid (like the current userId) in the message and when it's received I filter.
Send message:
let data = // whatever the data is the currentUID is sent along with it
let message = NWProtocolWebSocket.Metadata(opcode: .text)
let context = NWConnection.ContentContext(identifier: "send", metadata: [message])
connection.send(content: data, contentContext: context, isComplete: true, completion: .contentProcessed({ (error) in
if let error = error { return }
print("Successfully Sent: \(data.count) bytes")
}))
Receive message
connection.receive(minimumIncompleteLength: 1, maximumLength: 4200) { [weak self](data, context, isComplete, error) in
if let err = error { return }
if let data = data, !data.isEmpty {
// parse the data and if the uid in the data is equal to the current user's id then return
}
}

How to fix memory issues given by Instrument tools in Swift?

I have memory issues, especially for the error
XPC connection interrupted
The screen is freezing for a few seconds..
So, I've been learning how to use the Instruments tools and try to fix this error. However, I've been trying to find the error in my code and it's apparently not the fault of my code but maybe the libraries?
As a result of this test, I've got some warnings (the purple ones):
Memory Issues (3 leaked types):
- 1 instance of _DateStorage leaked (0x10b1eb060)
- 1 instance of OS_dispatch_data leaked (0x10b0b1ac0)
- 1 32-byte malloc block leaked (x10b1eb040)
Could you tell me how to fix these warnings, knowing there is no backtrace available? Or how could I find somewhere that could tell me to fix those?
EDIT:
Thanks to Instrument tools, I found the function that caused the problem! So, I don't know if it is really about memory or Idk but here's the function!
The accurate and useful error I get is : "Closure #1 in closure #1 in MessagesTableViewController.getLastMessages"
I found here What is a closure #1 error in swift?, the error is probably caused by forced optional types. So, I am going to try to remove those.
func getLastMessages(cell: ContactMessageTableViewCell, index: IndexPath) {
// first, we get the total number of messages in chatRoom
var numberOfMessagesInChatRoom = 0
let previousCellArray = self.tableView.visibleCells as! [ContactMessageTableViewCell]
var index1 = 0
var messages = [JSQMessage]()
var sortedMessages = [JSQMessage]()
var messagesSortedByChatRooms = [String: [JSQMessage]]()
var doesHaveMessagesCount = false
var doesHaveSortedMessagesCount = false
let firstQuery = Constants.refs.databaseChats.queryOrderedByKey()
_ = firstQuery.observe(.childAdded, with: { [weak self] snapshot in
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let text = data["text"],
let chatRoom = data["chatRoom"],
!text.isEmpty
{
if let message = JSQMessage(senderId: id, displayName: name, text: text)
{
messages.append(message)
var arrayVariable = [JSQMessage]()
// we wanna get all messages and put it in the array corresponding to the chat room key
if messagesSortedByChatRooms[chatRoom] != nil { // if there is already the chatRoom key in dictionary
if let message1 = messagesSortedByChatRooms[chatRoom] {
arrayVariable = message1
}
arrayVariable.append(message)
messagesSortedByChatRooms[chatRoom] = arrayVariable
} else { // if there isn't the chatRoom key
arrayVariable.append(message)
messagesSortedByChatRooms[chatRoom] = arrayVariable
}
}
}
DispatchQueue.main.async {
// we have to sort messages by date
for (chatRoom, messagesArray) in messagesSortedByChatRooms {
var loopIndex = 0
var lastMessage: JSQMessage?
var array = [JSQMessage]()
for message in messagesArray { // we run through the messages array
array.removeAll()
loopIndex += 1
if loopIndex != 1 {
if message.date > lastMessage!.date {
array.append(message)
messagesSortedByChatRooms[chatRoom] = array
} else {
array.append(lastMessage!)
messagesSortedByChatRooms[chatRoom] = array
}
} else {
lastMessage = message
if messagesArray.count == 1 {
array.append(message)
messagesSortedByChatRooms[chatRoom] = array
}
}
}
}
if !doesHaveMessagesCount {
//doesHaveMessagesCount = true
// we have the number of chats in database
let secondQuery = Constants.refs.databaseChats.queryOrderedByPriority()
_ = secondQuery.observe(.childAdded, with: { [ weak self] snapshot in
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let text = data["text"],
let chatRoom = data["chatRoom"],
!text.isEmpty
{
if let message = JSQMessage(senderId: id, displayName: name, text: text)
{
index1 += 1
if chatRoom != nil {
if let unwrappedSelf = self {
if unwrappedSelf.sortedChatRoomsArray.contains(chatRoom) {
sortedMessages.append(message)
for (chatRoomKey, messageArray) in messagesSortedByChatRooms {
unwrappedSelf.lastMessages[chatRoomKey] = messageArray[0]
}
}
}
}
if let unwrappedSelf = self {
if index1 == messages.count && chatRoom != unwrappedSelf.roomName {
sortedMessages.append(JSQMessage(senderId: id, displayName: name, text: "no message"))
}
}
}
}
DispatchQueue.main.async {
if let unwrappedSelf = self {
if !doesHaveSortedMessagesCount {
//doesHaveSortedMessagesCount = true
if unwrappedSelf.sortedChatRoomsArray.indices.contains(index.row) {
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]] != nil {
if unwrappedSelf.lastMessagesArray.count != 0 {
let currentChatRoom = unwrappedSelf.sortedChatRoomsArray[index.row]
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text != "no message" {
if UUID(uuidString: unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]!.text) == nil {
cell.contactLastMessageLabel.text = unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text
} else {
cell.contactLastMessageLabel.text = "New image"
}
} else {
cell.contactLastMessageLabel.text = ""
cell.contactLastMessageLabel.font = UIFont(name:"HelveticaNeue-Light", size: 16.0)
}
if unwrappedSelf.lastMessagesArray.indices.contains(index.row) {
if unwrappedSelf.lastMessagesArray[index.row] != unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text {
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.senderId != PFUser.current()?.objectId {
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text != "no message" {
cell.contactLastMessageLabel.font = UIFont(name:"HelveticaNeue-Bold", size: 16.0)
}
var numberOfDuplicates = 0
for cell in previousCellArray {
if cell.contactLastMessageLabel.text == unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text {
numberOfDuplicates += 1
}
}
if numberOfDuplicates == 0 {
if unwrappedSelf.selectedUserObjectId != "" {
unwrappedSelf.changeCellOrder(index: index.row, selectedUserObjectId: unwrappedSelf.selectedUserObjectId, lastMessage: unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]!.text)
} else {
unwrappedSelf.changeCellOrder(index: index.row, selectedUserObjectId: "none", lastMessage: unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]!.text)
}
} else {
unwrappedSelf.tableView.reloadData()
}
cell.activityIndicatorView.stopAnimating()
}
} else {
cell.contactLastMessageLabel.font = UIFont(name:"HelveticaNeue-Light", size: 16.0)
}
}
}
} else {
}
}
}
}
}
})
}
}
})
}
FINL EDIT: I put a closure inside of another closure so it created an infine loop ;)

textField Editing Changed not reacting fast enough (Asynchronous calls)

I have a textfield that queries a firebase database for existing users and then display a UIImage according to if the user is available or not. The problem is that once the async code loads, the textfield doesn't react on changed value.
example. If i type 12345 as a username, i don't query the database. Everything ok. If i add a 6 it queries firebase and it shows me the user is free. if i press backspace and have 12345 the textFieldChanged is triggered again, and database is not queried. All OK.
but the problem is, when i have 12345, and i type 6 and very fast back so i have 12345, the query is running and shows me the available icon (because the back was pressed very fast). Is this because of the Simulator or is it a real problem and can i be fixed easily ?
my code:
#IBAction func textFieldChanged(_ sender: UITextField) {
if let username = usernameInputText.text, username.count > 5 {
checkIfUserExists(username: username) { doesExist in //(2)
if doesExist! {
self.completeSignupButton.isEnabled = false
self.ifAvailableImageView.image = UIImage(named: "Close")
} else {
self.completeSignupButton.isEnabled = true
self.ifAvailableImageView.image = UIImage(named: "Check")
}
}
} else {
ifAvailableImageView.image = UIImage(named: "Close")
self.completeSignupButton.isEnabled = false
}
}
func checkIfUserExists(username: String, completion: #escaping (Bool?) -> Void) {
spinner.startAnimating()
self.ifAvailableImageView.image = nil
let docRef = db.collection("users").document(username)
docRef.getDocument { (document, error) in
if error != nil {
self.spinner.stopAnimating()
completion(nil)
} else {
self.spinner.stopAnimating()
if let document = document {
if document.exists {
completion(true)
} else {
completion(false)
}
}
}
}
}
You can just compare the username being processed with the current text in the text field and not process the result if it not the same because you only want to process the latest one.
#IBAction func textFieldChanged(_ sender: UITextField) {
if let username = usernameInputText.text, username.count > 5 {
checkIfUserExists(username: username) { doesExist in //(2)
// Check if current text and the completion being processed are for the same username
if username != sender.text {
return
}
if doesExist! {
self.completeSignupButton.isEnabled = false
self.ifAvailableImageView.image = UIImage(named: "Close")
} else {
self.completeSignupButton.isEnabled = true
self.ifAvailableImageView.image = UIImage(named: "Check")
}
}
} else {
ifAvailableImageView.image = UIImage(named: "Close")
self.completeSignupButton.isEnabled = false
}
}

Taking so much time when i insert 10k data in coredata ?

In my project concept i need a insert 10k data when user open the application. I integrate core data for storing data but its take 1 to 5 minutes.
Here is my code ?
func inserChatMessage(_ message: String, chatId: String, onCompletion completionHandler:((_ message: ChatMessage) -> Void)?) {
var objMessage: ChatMessage? = nil
if let obj = ChatMessage.createEntity() {
objMessage = obj
}
objMessage?.messageId = ""
objMessage?.message = message
objMessage?.chatId = chatId
objMessage?.senderId = AIUser.current.userId
objMessage?.createAt = Date()
objMessage?.updateAt = Date()
let cManager = CoreDataManager.sharedManager
cManager.saveContext()
if let completionHandler = completionHandler, let objMessage = objMessage {
completionHandler(objMessage)
}
}
Coredata is not a threadsafe. And as per your requirement you need to save large amount of data on app launch. So If you will save those data using main thread, your app will get hanged. So Instead on saving large amount of data on main thread you can save those data on background thread. Coredata is supporting multi threading concept by providing parent child context concept.
I have done same in one of my project and its working fine. Here i have attached code.
func savePersonalMessagesOnBackGroundThread(arrMessages:NSArray,responseData:#escaping () -> Void)
{
print(arrMessages)
let temporaryChatContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType)
temporaryChatContext.parent = self.managedObjectContext
temporaryChatContext.perform({() -> Void in
for i in 0..<arrMessages.count
{
let msgDic = arrMessages[i] as! NSDictionary
_ = self.saveMessageInLocalDB(dictMessage: msgDic, managedObjectContext: temporaryChatContext, onBackground: true)
if i == arrMessages.count - 1 {
do {
try temporaryChatContext.save()
runOnMainThreadWithoutDeadlock {
DLog(message: "Thred \(Thread.isMainThread)")
if(self.managedObjectContext.hasChanges)
{
self.saveContext()
responseData()
}
}
}
catch {
print(error)
}
}
}
})
}
func saveMessageInLocalDB(dictMessage:NSDictionary, managedObjectContext:NSManagedObjectContext,onBackground:Bool) -> Chat
{
var chatObj : Chat! = Chat()
var receiveId: Int32!
var flag:Bool = false
print(dictMessage)
// let predicate = NSPredicate(format:"uniqueId == %# and senderId = %d and receiverId = %d","\(dictMessage.value(forKey:keyuniqueId)!)",Int32(dictMessage.value(forKey:keysenderId) as! Int64),Int32(dictMessage.value(forKey:keyreceiverId) as! Int64))
let predicate = NSPredicate(format:"uniqueId == %#","\(dictMessage.value(forKey:keyuniqueId)!)")
let objContext = managedObjectContext
let fetchRequest = NSFetchRequest<Chat>(entityName: ENTITY_CHAT)
let disentity: NSEntityDescription = NSEntityDescription.entity(forEntityName: ENTITY_CHAT, in: objContext)!
fetchRequest.predicate = predicate
fetchRequest.entity = disentity
do{
let results = try managedObjectContext.fetch(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) as! [Chat]
if(results.count > 0)
{
chatObj = results[0]
chatObj.messageId = Int32(dictMessage.value(forKey:keymessageId) as! Int64)
chatObj.dateOnly = dictMessage.value(forKey:keydateOnly) as! String?
}
else{
//receiveId = Int32(dictMessage.value(forKey:keyreceiverId) as! Int64)
//self.createNewChatObject(dictMessage: dictMessage, receiverId: receiveId, managedObjectContext: managedObjectContext)
chatObj = NSEntityDescription.insertNewObject(forEntityName:ENTITY_CHAT,into: managedObjectContext) as? Chat
if dictMessage[keymessageId] != nil {
chatObj.messageId = dictMessage.value(forKey:keymessageId) as! Int32
}
if(chatObj.message?.length != 0)
{
chatObj.message = dictMessage.value(forKey:keychatMessage) as? String
}
chatObj.messageType = Int32(dictMessage.value(forKey:keymessageType) as! Int64)
chatObj.senderId = Int32(dictMessage.value(forKey:keysenderId) as! Int64)
if(chatObj.senderId != Int32((APP_DELEGATE.loggedInUser?.id!)!))
{
let contactObj = self.getContactByContactId(contactId: Int32(dictMessage.value(forKey:keysenderId) as! Int64))
if(contactObj == nil)
{
_ = self.saveUnknownUserASContact(msgDict: dictMessage as! Dictionary<String, Any>)
}
}
chatObj.receiverId = Int32(dictMessage.value(forKey:keyreceiverId) as! Int64)
chatObj.uniqueId = dictMessage.value(forKey:keyuniqueId) as? String
chatObj.mediaName = dictMessage.value(forKey:keymediaName) as? String
print(NSDate())
if dictMessage[keycreatedDate] != nil {
let utcDate : NSDate = DateFormater.getUTCDateFromUTCString(givenDate: dictMessage.value(forKey:keycreatedDate) as! String)
chatObj.createdDate = utcDate
chatObj.updatedDate = utcDate
}
else
{
chatObj.createdDate = NSDate()
chatObj.updatedDate = NSDate()
}
if(chatObj.senderId == Int32((APP_DELEGATE.loggedInUser?.id)!))
{
chatObj.chatUser = chatObj.receiverId
}
else
{
chatObj.chatUser = chatObj.senderId
}
if dictMessage[keystatus] != nil {
chatObj.status = Bool((dictMessage.value(forKey:keystatus) as! Int64) as NSNumber)
}
switch Int(chatObj.messageType)
{
case MSG_TYPE.MSG_Text.rawValue:
chatObj.cellType = (chatObj.senderId != Int32((APP_DELEGATE.loggedInUser?.id!)!) ? Int32(CELL_TYPE.CELL_TEXT_RECEIVER.rawValue) : Int32(CELL_TYPE.CELL_TEXT_SENDER.rawValue))
case MSG_TYPE.MSG_Image.rawValue:
chatObj.cellType = (chatObj.senderId != Int32((APP_DELEGATE.loggedInUser?.id!)!) ? Int32(CELL_TYPE.CELL_IMAGE_RECEIVER.rawValue) : Int32(CELL_TYPE.CELL_IMAGE_SENDER.rawValue))
self.saveMedia(chatObj: chatObj)
default :
// chatObj.cellType = Int32(CELL_TYPE.CELL_LOAD_MORE.rawValue)
break
}
}
// deviceMake = 1;
if(!onBackground)
{
self.saveContext()
}
}
catch
{
}
return chatObj
}
Using the basic example below I can insert 10k records very quickly. The main thing that has changed here compared to your code is that I loop through and create the entities and then call save() at the very end. So you are performing one write call to the db instead of 10k. You are writing more information in that one call but it is still much quicker.
import UIKit
import CoreData
class ViewController: UIViewController {
lazy var sharedContext: NSManagedObjectContext? = {
return (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext
}()
override func viewDidLoad() {
super.viewDidLoad()
if let messages = getMessages(), messages.count > 0 {
printMessages(messages: messages)
} else {
loadChatMessages()
printMessages(messages: getMessages())
}
}
private func printMessages(messages: [Message]?) {
guard let messages = messages else { return }
for message in messages {
print(message.message)
}
}
private func getMessages() -> [Message]? {
let request = NSFetchRequest<Message>(entityName: "Message")
let messages = try? self.sharedContext?.fetch(request)
return messages ?? nil
}
private func loadChatMessages() {
var counter = 1
while counter <= 10000 {
let message = Message(entity: Message.entity(), insertInto: self.sharedContext)
message.message = "This is message number \(counter)"
message.read = false
message.timestamp = Date()
counter = counter + 1
}
do {
try self.sharedContext?.save()
} catch {
print(error)
}
}
}
As mentioned in my comment above, you can improve this further by doing it in the background (see Twinkle's answer for an example of how to switch to a background thread), you can also provide a pre-filled (pre-seeded) core data database that already contains the 10k records with your app. so it doesn't need to load this on initial load.
To do this you would fill the db locally on your dev machine and then copy it to the project bundle. On initial load you can check to see if your db filename exists in the documents folder or not. If it doesn't copy it over from the bundle and then use that DB for core data.

Check the valid phone number

I have one text field for enter the phone number and user have to press OK button.
Then I write some function to check whether entered number is valid number or 10 digit number. And I don't want to add country code. That I have separately.
But when I press OK button its give me uialert - wrong number for all number including my own number. I don't know any code I missed?
func validate(value: String) -> Bool {
let PHONE_REGEX = "^\\d{3}-\\d{3}-\\d{4}$"
var phoneTest = NSPredicate(format: "SELF MATCHES %#", PHONE_REGEX)
var result = phoneTest.evaluateWithObject(value)
return result
}
#IBAction func confirmAction(sender: AnyObject) {
if validate(phoneNumber.text!)
{
print("Validate EmailID")
let phone = countryCode.text! + phoneNumber.text!
UserNetworkInterface().generateSms(phone, onCompletion: nil)
performSegueWithIdentifier("ConfirmSmsCode", sender: self)
}
else
{
print("invalide EmailID")
let alert = UIAlertView()
alert.title = "Message"
alert.message = "Enter Valid Contact Number"
alert.addButtonWithTitle("Ok")
alert.delegate = self
alert.show()
}
}
Updated :
#IBAction func confirmAction(sender: AnyObject) {
if let phoneNumberValidator = phoneNumber.isPhoneNumber
{
print("Validate EmailID")
let phone = countryCode.text! + phoneNumber.text!
UserNetworkInterface().generateSms(phone, onCompletion: nil)
performSegueWithIdentifier("ConfirmSmsCode", sender: self)
}
else
{
print("invalide EmailID")
let alert = UIAlertView()
alert.title = "Message"
alert.message = "Enter Valid Contact Number"
alert.addButtonWithTitle("Ok")
alert.delegate = self
alert.show()
phoneNumber.text = ""
}
// Number valid
}
Try this.
Make an extension to String.
Swift 4
extension String {
var isPhoneNumber: Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
let matches = detector.matches(in: self, options: [], range: NSRange(location: 0, length: self.count))
if let res = matches.first {
return res.resultType == .phoneNumber && res.range.location == 0 && res.range.length == self.count
} else {
return false
}
} catch {
return false
}
}
}
Older Swift Versions
extension String {
var isPhoneNumber: Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingType.PhoneNumber.rawValue)
let matches = detector.matchesInString(self, options: [], range: NSMakeRange(0, self.characters.count))
if let res = matches.first {
return res.resultType == .PhoneNumber && res.range.location == 0 && res.range.length == self.characters.count
} else {
return false
}
} catch {
return false
}
}
}
Usage:
override func viewWillAppear(animated: Bool) {
//Sample check
let phoneString = "8888888888"
let phoneNumberValidator = phoneString.isPhoneNumber
print(phoneNumberValidator)
}
Swift 3
For those of you who would like the phone number to have a minimum of 10 characters use the below code (Amended #Alvin George code)
extension String {
var isPhoneNumber: Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
let matches = detector.matches(in: self, options: [], range: NSMakeRange(0, self.characters.count))
if let res = matches.first {
return res.resultType == .phoneNumber && res.range.location == 0 && res.range.length == self.characters.count && self.characters.count == 10
} else {
return false
}
} catch {
return false
}
}
}
Usage
ooverride func viewDidLoad() {
super.viewDidLoad()
//Example
let phoneNumberString = "8500969696"
let phoneNumberValidation = phoneNumberString.isPhoneNumber
print(phoneNumberValidation)
// Prints: true
}
Try this for Indian 10 digit mobile number validation
var isValidMobileNo: Bool {
let PHONE_REGEX = "^[7-9][0-9]{9}$";
let phoneTest = NSPredicate(format: "SELF MATCHES %#", PHONE_REGEX)
let result = phoneTest.evaluate(with: self)
return result
}
Amended #Alvin George code for Swift 4 that also accepts only 10 digit phone numbers:
extension String {
var isPhoneNumber: Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
let matches = detector.matches(in: self, options: [], range: NSMakeRange(0, self.count))
if let res = matches.first {
return res.resultType == .phoneNumber && res.range.location == 0 && res.range.length == self.count && self.count == 10
} else {
return false
}
} catch {
return false
}
}
}
Easy validation for Indian 10 digit mobile number
func isValidPhone(testStr:String) -> Bool {
let phoneRegEx = "^[6-9]\\d{9}$"
var phoneNumber = NSPredicate(format:"SELF MATCHES %#", phoneRegEx)
return phoneNumber.evaluate(with: testStr)
}
Modifying #A.G's answer to update to Swift 5:
extension String {
func isValidPhone() -> Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
let matches = detector.matches(in: self, options: [], range: NSMakeRange(0, self.count))
if let res = matches.first {
return res.resultType == .phoneNumber && res.range.location == 0 && res.range.length == self.count
} else {
return false
}
} catch {
return false
}
}
}

Resources