In my iOS app, I want to search device using swift 3. How do I implement this functionality in my app using core Bluetooth?
this below code i what i wrote from rearching in internet and help of my friends to list bluetooth devices and connect to heart rate measure service
class HRMViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var cbCentralManager: CBCentralManager?
var cbPeripheral: CBPeripheral?
var discoveredPeripherals = [CBPeripheral]()
var connected = ""
var bodyData = ""
var manufacturer = ""
var deviceData = ""
var heartRate: UInt16 = 0
var localNameArray = [String]()
var pulseTimer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// Do any additional setup after loading the view.
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.backgroundColor = UIColor.lightGray
tableView.layer.borderColor = UIColor.lightGray.cgColor
tableView.layer.borderWidth = 1.0
tableView.layer.cornerRadius = 2.0
tableView.layer.masksToBounds = true
let centralManager = CBCentralManager(delegate: self, queue: nil)
self.cbCentralManager = centralManager
}
}
extension HRMViewController : CBCentralManagerDelegate, CBPeripheralDelegate {
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
let localName = advertisementData[CBAdvertisementDataLocalNameKey] as? String ?? ""
if localName.count > 0 {
if RSSI.intValue > signalStrengthMax {
if let index = self.discoveredPeripherals.index(of: peripheral) {
self.discoveredPeripherals.remove(at: index)
self.localNameArray.remove(at: index)
self.tableView.reloadData()
}
return
}
if RSSI.intValue < signalStrengthMin {
if let index = self.discoveredPeripherals.index(of: peripheral) {
self.discoveredPeripherals.remove(at: index)
self.localNameArray.remove(at: index)
self.tableView.reloadData()
}
return
}
print("Discovered: \(peripheral.name ?? "a device") with udid: \(peripheral.identifier) at \(RSSI)")
if !(self.discoveredPeripherals.contains(peripheral)) {
self.discoveredPeripherals.append(peripheral)
self.localNameArray.append(localName)
self.tableView.reloadData()
}
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices(nil)
self.connected = "Connected: \((peripheral.state == .connected) ? "Yes" : "No")"
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state != .poweredOn {
return
}
if central.state == .poweredOn {
let deviceService = CBUUID(string: HRMConstants.Services.deviceInfoUUID)
let heartRateService = CBUUID(string: HRMConstants.Services.heartRateUUID)
let services = [deviceService,heartRateService]
cbCentralManager?.scanForPeripherals(withServices: services, options: nil)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services ?? [CBService]() {
peripheral.discoverCharacteristics(nil, for: service)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if service.uuid == CBUUID(string: HRMConstants.Services.heartRateUUID) {
for character in service.characteristics ?? [CBCharacteristic]() {
if character.uuid == CBUUID(string: HRMConstants.Characteristics.measurementUUID) {
self.cbPeripheral?.setNotifyValue(true, for: character)
}
else if character.uuid == CBUUID(string: HRMConstants.Characteristics.bodyLocationUUID) {
self.cbPeripheral?.readValue(for: character)
}
}
}
if service.uuid == CBUUID(string: HRMConstants.Services.deviceInfoUUID) {
for character in service.characteristics ?? [CBCharacteristic]() {
if character.uuid == CBUUID(string: HRMConstants.Characteristics.manufacturerNameUUID) {
self.cbPeripheral?.readValue(for: character)
}
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic.uuid == CBUUID(string: HRMConstants.Characteristics.measurementUUID) {
self.getHeartRateData(for: characteristic, error: error)
}
if characteristic.uuid == CBUUID(string: HRMConstants.Characteristics.manufacturerNameUUID) {
self.getManufacturerName(for: characteristic)
}
else if characteristic.uuid == CBUUID(string: HRMConstants.Characteristics.bodyLocationUUID) {
self.getBodyLocation(for: characteristic)
}
}
}
extension HRMViewController {
func getHeartRateData(for characteristic: CBCharacteristic, error: Error?) {
if let _ = error {
print("Error: \(error?.localizedDescription ?? "Unknown")")
return
}
guard let value = characteristic.value else { return }
let bpm : UInt16
if (value[0] & 0x01) == 0 {
bpm = UInt16(value[1])
} else {
bpm = UInt16(littleEndian: value.subdata(in: 1..<3).withUnsafeBytes { $0.pointee } )
}
heartRate = bpm
doHeartBeat()
pulseTimer = Timer.scheduledTimer(timeInterval: 60.0 / Double(heartRate), target: self, selector: #selector(self.doHeartBeat), userInfo: nil, repeats: false)
/*
var reportData = [UInt8](value)
var bpm: UInt16 = 0
if (reportData[0] & 0x01) == 0 {
bpm = UInt16(reportData[1])
}
else {
bpm = CFSwapInt16LittleToHost(UInt16(reportData[1]))
}
heartRate = bpm
doHeartBeat()
pulseTimer = Timer.scheduledTimer(timeInterval: 60.0 / Double(heartRate), target: self, selector: #selector(self.doHeartBeat), userInfo: nil, repeats: false)
*/
}
func getManufacturerName(for characteristic: CBCharacteristic) {
guard let value = characteristic.value else { return }
let manufacturerName = String(data: value, encoding: .utf8)
}
func getBodyLocation(for characteristic: CBCharacteristic) {
guard let value = characteristic.value else { return }
var location = ""
// 1
var bodyData = [UInt8](value)
if !bodyData.isEmpty {
let bodyLocation: UInt8 = bodyData[0]
// 2
location = "Body Location: \(bodyLocation == 1 ? "Chest" : "Undefined")"
// 3
}
else {
// 4
location = "Body Location: N/A"
}
print(location)
}
#objc func doHeartBeat() {
}
}
extension HRMViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text = "\(localNameArray[indexPath.row]) \(discoveredPeripherals[indexPath.row].identifier )"
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let newPeripheral = discoveredPeripherals[indexPath.row]
if let _ = cbPeripheral { // had a device selected already
if newPeripheral != cbPeripheral! { // clean up old peripheral
self.cleanUp()
}
}
cbPeripheral = newPeripheral
self.cbCentralManager?.stopScan()
cbPeripheral?.delegate = self
self.cbCentralManager?.connect(cbPeripheral!, options: nil)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return discoveredPeripherals.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 45.0
}
func cleanUp() {
if !(cbPeripheral!.state == .connected) { // Don't do anything if we're not connected
return
}
if let services = self.cbPeripheral!.services {
for eachService in services {
if let characteristics = eachService.characteristics {
for eachCharacteristic in characteristics {
if eachCharacteristic.uuid.isEqual(CBUUID(string: HRMConstants.Characteristics.bodyLocationUUID)) {
if eachCharacteristic.isNotifying {
self.cbPeripheral?.setNotifyValue(false, for: eachCharacteristic)
}
}
if eachCharacteristic.uuid.isEqual(CBUUID(string: HRMConstants.Characteristics.manufacturerNameUUID)) {
if eachCharacteristic.isNotifying {
self.cbPeripheral?.setNotifyValue(false, for: eachCharacteristic)
}
}
if eachCharacteristic.uuid.isEqual(CBUUID(string: HRMConstants.Characteristics.measurementUUID)) {
if eachCharacteristic.isNotifying {
self.cbPeripheral?.setNotifyValue(false, for: eachCharacteristic)
}
}
}
}
}
}
self.cbCentralManager?.cancelPeripheralConnection(self.cbPeripheral!)
self.cbPeripheral = nil
}
}
and for constants
struct HRMConstants {
struct Services {
static let deviceInfoUUID = "180A"
static let heartRateUUID = "180D"
}
struct Characteristics {
static let measurementUUID = "2A37"
static let bodyLocationUUID = "2A38"
static let manufacturerNameUUID = "2A29"
}
}
with this you will get the basic idea and then you can try it for yourself
see for ble doc for different bluetooth services
Related
I'm trying to populate my table view with the return of my HealthKit from Apple Health. I currently get the date and heart rate from Apple Health from the past 7 days. I can see everything clearly in my console.
Here's my block code:
func getTodaysHeartRate(completion: (#escaping (HKQuantitySample) -> Void)) {
print("func")
let heartRateUnit:HKUnit = HKUnit(from: "count/min")
let heartRateType:HKQuantityType = HKQuantityType.quantityType(forIdentifier: .heartRate)!
let startDate = Date() - 7 * 24 * 60 * 60
let endDate = Date()
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: [])
let sortDescriptors = [
NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
]
let heartRateQuery = HKSampleQuery(sampleType: heartRateType,
predicate: predicate,
limit: Int(HKObjectQueryNoLimit),
sortDescriptors: sortDescriptors)
{ (query:HKSampleQuery, results:[HKSample]?, error:Error?) -> Void in
guard error == nil else { print("error"); return }
//print("results")
//print(results!)
for result in results! {
guard let currData:HKQuantitySample = result as? HKQuantitySample else { return }
print("Heart Rate: \(currData.quantity.doubleValue(for: heartRateUnit))")
print("Times: \(currData.startDate)")
//print("End Date: \(currData.endDate)")
//print("quantityType: \(currData.quantityType)")
//print("Metadata: \(String(describing: currData.metadata))")
//print("UUID: \(currData.uuid)")
//print("Source: \(currData.sourceRevision)")
//print("Device: \(String(describing: currData.device))")
//print("---------------------------------\n")
}
}
healthStore.execute(heartRateQuery)
}
#IBOutlet weak var heartRate: UILabel!
#IBAction func getHeartRate(_ sender: Any) {
getTodaysHeartRate { (result) in
print("\(result)")
DispatchQueue.main.async {
self.heartRate.text = "\(result)"
}
}
}
#IBAction func emailResult(_ sender: Any) {
self.sendEmail()
}
Here I have created as sample project for you where I made some changes with your code which is shown below and comments are added for that:
import UIKit
import HealthKit
class ViewController: UIViewController {
//add a tableview to your storyboard and connect delegate and datasource
#IBOutlet weak var tblHeartRateData: UITableView!
let healthStore = HKHealthStore()
//create an array of HKSample which will hold your data from healthkit or you can create a custom class for that
var heartRateData: [HKSample]?
override func viewDidLoad() {
super.viewDidLoad()
//Get data access permission
getHealthKitPermission()
}
#IBAction func getHeartRate(_ sender: Any) {
getTodaysHeartRate { (result) in
DispatchQueue.main.async {
//Here you will get your healthkit data.
self.heartRateData = result
//Once you get it reload your table view
self.tblHeartRateData.reloadData()
}
}
}
//Permission
func getHealthKitPermission() {
let healthkitTypesToRead = NSSet(array: [
HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) ?? ""
])
healthStore.requestAuthorization(toShare: nil, read: healthkitTypesToRead as? Set) { (success, error) in
if success {
print("Permission accept.")
} else {
if error != nil {
print(error ?? "")
}
print("Permission denied.")
}
}
}
func getTodaysHeartRate(completion: (#escaping ([HKSample]) -> Void)) {
print("func")
let heartRateType:HKQuantityType = HKQuantityType.quantityType(forIdentifier: .heartRate)!
//predicate
let startDate = Date() - 2 * 24 * 60 * 60
let endDate = Date()
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: [])
//descriptor
let sortDescriptors = [
NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
]
let heartRateQuery = HKSampleQuery(sampleType: heartRateType,
predicate: predicate,
limit: Int(HKObjectQueryNoLimit),
sortDescriptors: sortDescriptors)
{ (query:HKSampleQuery, results:[HKSample]?, error:Error?) -> Void in
guard error == nil else { print("error"); return }
//Here I have added completion which will pass data when button will tap.
completion(results!)
}
healthStore.execute(heartRateQuery)
}
}
//TableView Methods.
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return heartRateData?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HeartDataTableViewCell
let heartRateUnit:HKUnit = HKUnit(from: "count/min")
let heartData = self.heartRateData?[indexPath.row]
guard let currData:HKQuantitySample = heartData as? HKQuantitySample else { return UITableViewCell()}
cell.lblHeartRate.text = "Heart Rate: \(currData.quantity.doubleValue(for: heartRateUnit))"
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 106
}
}
for more info check our THIS demo project.
And your result will be:
how to do search function in textfield using mvvm method in the swift3.
i have listed the data in the tableview from the api.But i need to implement searching the tableview on textfield action .so how to do viewmodel and viewcontroller.
my viewmodel:-
class ViewModel: NSObject {
var datasourceModel:DataSourceModel
init(withdatasource newDatasourceModel: DataSourceModel) {
datasourceModel = newDatasourceModel
}
func datafordisplay(atindex indexPath: IndexPath) -> Model{
return datasourceModel.dataListArray![indexPath.row]
}
func numberOfRowsInSection(section:Int) -> Int {
return (datasourceModel.dataListArray?.count)!
}
func search(completion :#escaping (_ isSearching:Bool) -> ()) {
loadFromWebserviceData { (newDataSourceModel) in
if(newDataSourceModel != nil)
{
self.datasourceModel = newDataSourceModel!
completion(true)
}
else{
completion(false)
}
}
}
func loadData(completion :#escaping (_ isSucess:Bool) -> ()){
loadFromWebserviceData { (newDataSourceModel) in
if(newDataSourceModel != nil)
{
self.datasourceModel = newDataSourceModel!
completion(true)
}
else{
completion(false)
}
}
}
//}
func loadFromWebserviceData(completion :#escaping (DataSourceModel?) -> ()){
//with using Alamofire ..............
Alamofire.request("http://www.example").validate(statusCode: 200..<300).validate(contentType: ["application/json"]).responseJSON{ response in
switch response.result{
case .success(let data):
print("success",data)
let result = response.result
if let wholedata = result.value as? [String:Any]{
if let data = wholedata["data"] as? Array<[String:Any]>{
// print(data["name"] as! String)
print(data)
print(response)
let newDataSource:DataSourceModel = DataSourceModel(array: data)
completion(newDataSource)
// }
}
}
// case .failure(let data):
// print("fail",data)
case .failure(let encodingError ):
print(encodingError)
// if response.response?.statusCode == 404{
print(encodingError.localizedDescription)
completion(nil)
// }
}
}}
}
my viewcontroller:-
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource, UISearchBarDelegate,UITextFieldDelegate {
#IBOutlet private weak var tableView: UITableView!
#IBOutlet weak var txt: UITextField!
private var searchViewModel :ViewModel!
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?, withViewModel viewModel:ViewModel) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
searchViewModel = viewModel
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "SEARCH"
txt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
searchViewModel.loadData { (isSuccess) in
if(isSuccess == true)
{
self.tableView.reloadData()
}
else{
}
}
}
#objc private func textFieldDidChange(textField: UITextField) {
if textField.text == "" {
self .viewDidLoad()
}
else{
filterContentForSearchText(searchText: textField.text!)
}
}
func filterContentForSearchText(searchText: String) {
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchViewModel.numberOfRowsInSection(section: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "searchcell"
var cell: SearchCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? QM_SearchCell
if cell == nil {
tableView.register(UINib(nibName: "SearchCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? SearchCell
}
cell.setsearchData(search: searchViewModel.datafordisplay(atindex: indexPath))
return cell
}
and my datasource:-
var dataListArray:Array<Model>? = []
init(array :Array<[String:Any]>?) {
super.init()
var newArray:Array<[String:Any]> = []
if array == nil{
// newArray = self.getJsonDataStored44()
}
else{
newArray = array!
}
var datalist:Array<Model> = []
for dict in newArray{
let model = Model(dictionary: dict)
datalist.append(model)
}
self.dataListArray = datalist
}
}
this is my code ..so what is the changes needed in the viewmodel ,no of section in tableview,cell for row at tableview and the function while clicking the textfeild.
in watchOS, i am just trying to get HR value in real-time while a workoutSession is running.
func startHeartRateQuery(updateHandler: #escaping ([HKQuantitySample]?) -> Void) {
guard let quantityType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
return
}
let heartRateQuery = HKAnchoredObjectQuery(type: quantityType, predicate: nil, anchor: anchor, limit: Int(HKObjectQueryNoLimit)) { (query, sampleObjects, deletedObjects, newAnchor, error) -> Void in
guard let newAnchor = newAnchor else {return}
self.anchor = newAnchor
updateHandler(sampleObjects as? [HKQuantitySample])
}
heartRateQuery.updateHandler = {(query, samples, deleteObjects, newAnchor, error) -> Void in
self.anchor = newAnchor!
updateHandler(samples as? [HKQuantitySample])
}
healthStore.execute(heartRateQuery)
activeDataQueries.append(heartRateQuery)
}
And This is how i do start workoutSession.
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
guard let d = delegate else {
return
}
if let u = userInfo["status"] as? String {
d.receivedWorkoutRunningStatus(u)
}
if let c = userInfo["clock"] as? String {
d.receiveWorkoutRestPeriodClock(c)
}
}
You can find receivedWorkoutRunningStatus function on InterfaceController.
This is InterfaceController.swift which is first screen on Watch App.
class InterfaceController: WKInterfaceController, HKWorkoutSessionDelegate {
#IBOutlet var lblHeartRate: WKInterfaceLabel!
#IBOutlet var lblSplitIntervalNumber: WKInterfaceLabel!
#IBOutlet var lblRestPeriodClock: WKInterfaceLabel!
private let healthStoreManager = WatchHealthKitManager()
private let parentConnector = ParentConnector()
private var workoutSession: HKWorkoutSession!
override func awake(withContext context: Any?) {
super.awake(withContext: context)
// Create a workout session with the workout configuration
do {
let workoutConfiguration = HKWorkoutConfiguration()
workoutConfiguration.locationType = .indoor
workoutConfiguration.activityType = .rowing
workoutSession = try HKWorkoutSession(configuration: workoutConfiguration)
} catch {
fatalError(error.localizedDescription)
}
//// initial setup
parentConnector.activate()
parentConnector.delegate = self
workoutSession.delegate = self
}
// MARK: - Data Accumulation
private func startAccumulatingData() {
healthStoreManager.startHeartRateQuery() { quantitySamples in
DispatchQueue.main.async {
guard !self.isPaused() else {
return
}
guard let heartRateSamples = quantitySamples else {
return
}
let hrUnit = HKUnit(from: "count/min")
guard let sample = heartRateSamples.first else {
return
}
let value = sample.quantity.doubleValue(for: hrUnit)
self.updateHeartRate(value: value)
self.parentConnector.transfer(value: value)
}
}
}
func workoutSession(_ workoutSession: HKWorkoutSession,
didChangeTo toState: HKWorkoutSessionState,
from fromState: HKWorkoutSessionState,
date: Date) {
switch (toState) {
case .running:
startAccumulatingData()
case .ended:
stopAccumulatingData()
default:
print("Error")
}
}
func receivedWorkoutRunningStatus(_ status: String) {
if (status == "Start") {
healthStoreManager.start(workoutSession)
} else if (status == "Finish") {
healthStoreManager.end(workoutSession)
lblHeartRate.setText("No Active Workout")
}
DispatchQueue.main.async {
self.lblSplitIntervalNumber.setText(status)
}
}
On the iPhone App, I send a "Start" string using transferUserInfo function to trigger the workoutSession beginning. This is not working properly, it only sometimes works, it is very inconsistent.
I would appreciate if you have any advice or alternative approaches.
Thank you in advance.
I am trying to set data on tableview dynamically and cell can be deleted by swiping.cell create multiple layer and after deletion some layer is exist,its appear cell has not deleted.
my code is here ..
override func viewDidLoad() {
super.viewDidLoad()
self.beaconArrayM = NSMutableArray()
self.produsctListM = NSMutableArray()
self.contentArrayM = NSMutableArray()
self.fatchDataFromApiAsync(urlString: videoUrl)//video url
countBeacons = 0
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(_ animated: Bool) {
}
func fatchDataFromApiAsync(urlString:String) {
_ = NSArray()
let url:URL = URL(string: urlString)!
URLSession.shared.dataTask(with: url){ data,response,error in
if error != nil {
print("Data Parsing error = \(error)")
}
else{
do{
let jsonResponse = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:AnyObject]
if jsonResponse["assets"] != nil{
self.jsonArray = jsonResponse["assets"] as! NSArray
self.HeaderStr = jsonResponse["identifier"] as? String
self.navigationController?.navigationBar.topItem?.title = self.HeaderStr
self.beaconManager.delegate = self
self.swipeTableview.delegate = self
self.swipeTableview.dataSource = self
}
}
catch let error as NSError{
print("\(error)")
}
}
}.resume()
}
}
extension DemoListBeaconsVC: ESTBeaconManagerDelegate
{
// :MARK BeaconsManager ranging delegates
func beaconManager(_ manager: Any, didEnter region: CLBeaconRegion) {
countBeacons += 1
if !(region.minor == nil){
let minorValue = region.minor
if !(self.beaconArrayM.contains(minorValue!)){
self.beaconArrayM .add(minorValue!)
}
self.contentArrayM = self.beaconArrayM
self.swipeTableview.reloadData()
}
}
func downloadImage(url: URL,indexPath: IndexPath,productTxt : String) {
let cell = self.swipeTableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SwipeTableViewCell
print("Download Started")
getDataFromUrl(url: url) { (data, response, error) in
guard let data = data, error == nil else { return }
print(response?.suggestedFilename ?? url.lastPathComponent)
print("Download Finished")
DispatchQueue.main.async() { () -> Void in
cell.productImage.contentMode = .scaleAspectFit
cell.productImage.image = UIImage(data: data)
cell.contentLbl.text = productTxt
}
}
}
func getDataFromUrl(url: URL, completion: #escaping (_ data: Data?, _ response: URLResponse?, _ error: Error?) -> Void) {
URLSession.shared.dataTask(with: url) {
(data, response, error) in
completion(data, response, error)
}.resume()
}
func beaconManager(_ manager: Any, didExitRegion region: CLBeaconRegion) {
countBeacons -= 1
// if countBeacons == 0{
// }
if (((self.beaconArrayM.count)) > 0 && !(region.minor == nil)){
self.beaconArrayM.remove(region.minor!)
self.contentArrayM = self.beaconArrayM
self.swipeTableview.reloadData()
}
}
func beaconManager(_ manager: Any, didDetermineState state: CLRegionState, for region: CLBeaconRegion) {
switch state {
case CLRegionState.inside:
if region == beaconRegion
{
self.beaconManager.startMonitoring(for: beaconRegion)
}
else if region == beaconRegion
{
self.beaconManager.startMonitoring(for: beaconRegion2)
}
else if region == beaconRegion
{
self.beaconManager.startMonitoring(for: beaconRegion3)
}
print("inside REGION",region.description)
break
case CLRegionState.outside:
// Stop Monitoring
if region == beaconRegion
{
self.beaconManager.stopMonitoring(for: beaconRegion)
}
else if region == beaconRegion
{
self.beaconManager.stopMonitoring(for: beaconRegion2)
}
else if region == beaconRegion
{
self.beaconManager.stopMonitoring(for: beaconRegion3)
}
print("outside REGION",region.description)
break
case CLRegionState.unknown:
print("unknown REGION",region.description)
break
}
}
func beaconManager(_ manager: Any, didChange status: CLAuthorizationStatus) {
switch status {
case .authorizedAlways:
self.beaconManager.requestAlwaysAuthorization()
print("authorizedAlways")
break
default:
print("defaultt")
break
}
}
func beaconManager(_ manager: Any, rangingBeaconsDidFailFor region: CLBeaconRegion?, withError error: Error) {
}
func beaconManager(_ manager: Any, didFailWithError error: Error) {
}
func beaconManager(_ manager: Any, didStartMonitoringFor region: CLBeaconRegion) {
if region == beaconRegion
{
self.beaconManager.requestState(for: beaconRegion)
}
else if region == beaconRegion
{
self.beaconManager.requestState(for: beaconRegion2)
}
else if region == beaconRegion
{
self.beaconManager.requestState(for: beaconRegion3)
}
}
func beaconManager(_ manager: Any, monitoringDidFailFor region: CLBeaconRegion?, withError error: Error) {
}
}
//: MARK Tableview delegate and datasource
extension DemoListBeaconsVC : UITableViewDataSource, UITableViewDelegate
{
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Cell"
// print("Begin cellForRowAt")
let cell = self.swipeTableview.dequeueReusableCell(withIdentifier: identifier) as! SwipeTableViewCell
if (self.contentArrayM.count) > 0 {
var currentIndex: Int = 0
let countIndex: Int = 0
for tempp in self.contentArrayM{
let temp = jsonArray .object(at: indexPath.row)
self.jsonDic = temp as! NSDictionary
self.minor = self.jsonDic["minor"] as? String
if let minorInteger = Int(self.minor!) {
minorNumber = NSNumber(value:minorInteger)
}
if minorNumber == tempp as! NSNumber
{
currentIndex = countIndex
break
}
}
// let temp = jsonArray .object(at: currentIndex)
let temp = jsonArray .object(at: indexPath.row)
self.jsonDic = temp as! NSDictionary
self.minor = self.jsonDic["minor"] as? String
self.HeaderStr = self.jsonDic["title"] as? String
self.urlStr = self.jsonDic["url"] as? String
print("minor",self.minor!)
if let minorInteger = Int(self.minor!) {
minorNumber = NSNumber(value:minorInteger)
}
}
let url = NSURL(string: self.urlStr!)
downloadImage(url: url as! URL, indexPath: indexPath, productTxt: self.HeaderStr!)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 100.0
}
func actionGesture(recognizer: UITapGestureRecognizer)
{
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let temp = jsonArray .object(at: indexPath.row)
self.jsonDic = temp as! NSDictionary
self.HeaderStr = self.jsonDic["title"] as? String
self.urlStr = self.jsonDic["url"] as? String
let demoVC = self.storyboard?.instantiateViewController(withIdentifier: "ProductDetalsVC") as! ProductDetalsVC
demoVC.productTitle = self.HeaderStr
demoVC.imageStr = self.urlStr
self.navigationController?.pushViewController(demoVC, animated: true)
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .normal, title: "Delete")
{ action, index in
// print("delete")
self.swipeTableview.beginUpdates()
self.contentArrayM.removeObject(at: indexPath.row)
self.swipeTableview.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
print("array count after deletion",self.contentArrayM.count)
// self.swipeTableview.reloadRows(at: [indexPath], with: UITableViewRowAnimation.fade)
self.swipeTableview.endUpdates()
}
let done = UITableViewRowAction(style: .default, title: "Done")
{ action, index in
print("done")
}
return [delete, done]
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// the cells you would like the actions to appear needs to be editable
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
self.contentArrayM.remove(at: indexPath.row)
self.swipeTableview.deleteRows(at: [indexPath], with: .automatic)
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.contentArrayM.count == 0
{
return 0
}
else
{
return self.contentArrayM.count
}
}
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
}
I have found the answer finally.
I was created tableview cell two time , First in cellForRowAtIndexPath and Second in function downloadImage().
Now i am sending cell into function downloadImage() as follow.
downloadImage(cell: cell, url: url!, indexPath: indexPath, productTxt: self.headerStr!)
i am having in table view which will display the data from one url.But when i open first time.I am seeing two times same data or some time no data are showing in my table view.
import UIKit
import CoreLocation
class ContainerViewController: UIViewController, CLLocationManagerDelegate, UITableViewDelegate, UITableViewDataSource {
// check the current view controller
weak var currentViewController: UIViewController?
// show the location
#IBOutlet weak var LocationLabel: UILabel!
var locationManager: CLLocationManager = CLLocationManager()
#IBOutlet var TypeLabel: UILabel!
#IBOutlet var TableViewList: UITableView!
var startLocation: CLLocation!
var NewCurrentLatitude: Double!
var NewCurrentLongitude: Double!
var BTdata = BTData?()
var BTypeId : String?
// array to store the value from json
var arrDict = [Businessdata]()
var selectedIndex:NSIndexPath?
override func viewDidLoad() {
super.viewDidLoad()
isSearching = false;
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
startLocation = nil
// nib for custom cell (table view)
let nib = UINib(nibName:"customCell", bundle: nil)
TableViewList.registerNib(nib, forCellReuseIdentifier: "cell")
// LoadBusinesses()
}
override func viewDidAppear(animated: Bool)
{
self.TypeLabel.text = BTdata?.BTNames
self.BTypeId = BTdata?.BTIds
locationManager.startUpdatingLocation()
}
// current location
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location : CLLocationCoordinate2D = manager.location!.coordinate;
CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in
if (error != nil)
{
print("Reverse geocoder failed with error" + error!.localizedDescription)
return
}
if placemarks!.count > 0
{
let pm : CLPlacemark = placemarks![0]
//stop updating location to save battery life
let locality = (pm.locality != nil) ? pm.locality : ""
let state = pm.administrativeArea
let countryCode = pm.ISOcountryCode
if(countryCode == "CAN")
{
self.LocationLabel.text = "in "+locality!+", "+state!
self.NewCurrentLongitude = location.longitude;
self.NewCurrentLatitude = location.latitude;
}
else
{
self.LocationLabel.text = "in Toronto, ON"
self.NewCurrentLatitude = 43.761539;
self.NewCurrentLongitude = -79.411079;
print("Manual location Label.")
}
self.locationManager.stopUpdatingLocation()
}
else
{
print("Problem with the data received from geocoder")
}
self.LoadBusinesses()
NSUserDefaults.standardUserDefaults().setDouble(self.NewCurrentLongitude, forKey: "UserLongitude")
NSUserDefaults.standardUserDefaults().setDouble(self.NewCurrentLatitude, forKey: "UserLatitude")
NSUserDefaults.standardUserDefaults().synchronize()
})
}
// location load failure
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print("Error while updating location " + error.localizedDescription)
}
// web services method
func LoadBusinesses()
{
print("Inside Load Business")
let token = NSUserDefaults.standardUserDefaults().valueForKey("access_token") as! String
let headers = ["x-access-token": token]
var StringUrl:String = "http:some url"
StringUrl += "?lat=\(self.NewCurrentLatitude)"
StringUrl += "&long=\(self.NewCurrentLongitude)"
print(StringUrl)
let request = NSMutableURLRequest(URL: NSURL(string: StringUrl)!,
cachePolicy: .UseProtocolCachePolicy,
timeoutInterval: 10.0)
request.HTTPMethod = "GET"
request.allHTTPHeaderFields = headers
let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
if (error != nil)
{
print(error)
}
else
{
if let json = (try? NSJSONSerialization.JSONObjectWithData(data!, options: [])) as? NSDictionary
{
let success = json["success"] as? Int
if (success == 1)
{
if let reposArray = json["data"] as? [NSDictionary]
{
self.arrDict.removeAll()
for item in reposArray
{
let itemObj = item as? Dictionary<String,AnyObject>
let b_type = itemObj!["business_type"]
// taxis type
if (b_type as? String == self.BTypeId)
{
self.arrDict.append(Businessdata(json:item))
print("load data")
}
}
dispatch_async(dispatch_get_main_queue(),{
self.TableViewList.reloadData()
print("load data 1")
})
}
}
else
{
let message = json["message"] as? String
print(message)
}
}
}
})
dataTask.resume()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
print("load data 2")
return self.arrDict.count
}
// number of rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
// calling each cell based on tap and users ( premium / non premium )
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
print("load data 3")
let cell:customCell = self.TableViewList.dequeueReusableCellWithIdentifier("cell") as! customCell
cell.vendorName.text = arrDict[indexPath.row].BusinessName
cell.vendorAddress.text = arrDict[indexPath.row].Address
cell.VendorRating.rating = arrDict[indexPath.row].Rating!
return cell
}
// height of cell based on tap
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
if(isTapped == true && selectedIndex == indexPath)
{
return 125.0;
}
return 80.0;
}
// did select row of table view
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
selectedIndex = indexPath;
isTapped = true;
print("load data 4")
// TableViewList.reloadData();
}
}
My full code .In this same problem also i am facing.Showing same data 3 time .In my consloe, the print function is also printing two time.I measn that function executing two times:
load data 2
load data 2
load data 2
Manual location Label.
Inside Load Business
http://some url?lat=43.761539&long=-79.411079
load data
load data 2
load data 1
load data 3
0
1
2
3
4
Your code should be something like this. You should reload your tableView after you have parsed the data.
if let reposArray = json["data"] as? [NSDictionary] {
self.arrDict.removeAll()
for item in reposArray {
let itemObj = item as? Dictionary<String,AnyObject>
let b_type = itemObj!["business_type"]
// taxis type
if (b_type as? String == self.BTypeId) {
self.arrDict.append(Businessdata(json:item))
}
}
dispatch_async(dispatch_get_main_queue(),{
self.TableViewList.reloadData()
})
}