I have created a feature service on ArcGIS online which has approximately 2000 features. Each feature has four fields: name, latitude, longitude and a boolean validation field (true/false). Two custom symbols are used - one for validated features and one for non-validated features.
I have successfully connected to the feature service from my native (xcode/swift) iOS application and the features are displayed properly on top of the basemap.
I have implemented a touch delegate and successfully detect when a feature symbol is tapped. The issue I am having is trying to query (read) the "name" field attribute associated with the symbol that was tapped. I have tried using the code below but have not been able to read the attribute:
func geoView(_ geoView: AGSGeoView, didTapAtScreenPoint screenPoint: CGPoint, mapPoint: AGSPoint) {
if let activeSelectionQuery = activeSelectionQuery {
activeSelectionQuery.cancel()
}
guard let featureLayer = featureLayer else {
return
}
//tolerance level
let toleranceInPoints: Double = 12
//use tolerance to compute the envelope for query
let toleranceInMapUnits = toleranceInPoints * viewMap.unitsPerPoint
let envelope = AGSEnvelope(xMin: mapPoint.x - toleranceInMapUnits,
yMin: mapPoint.y - toleranceInMapUnits,
xMax: mapPoint.x + toleranceInMapUnits,
yMax: mapPoint.y + toleranceInMapUnits,
spatialReference: viewMap.map?.spatialReference)
//create query parameters object
let queryParams = AGSQueryParameters()
queryParams.geometry = envelope
//run the selection query
activeSelectionQuery = featureLayer.selectFeatures(withQuery: queryParams, mode: .new) { [weak self] (queryResult: AGSFeatureQueryResult?, error: Error?) in
if let error = error {
print("error: ",error)
}
if let result = queryResult {
print("\(result.featureEnumerator().allObjects.count) feature(s) selected")
print("name: ", result.fields)
}
}
}
I am using the ArGIS iOS 100.6 SDK.
Any help would be appreciated in solving this issue.
The featureLayer selection methods merely update the map view display to visually highlight the features.
From the featureLayer, you should get the featureTable and then call query() on that. Note that there are two methods. A simple query() that gets minimal attributes back, or an override on AGSServiceFeatureTable that allows you to specify that you want all fields back. You might need to specify .loadAll on that override to get the name field back. We do it this way to avoid downloading too much information (by default we download enough to symbolize and label the feature).
Related
I need to get the data from AKMicrophone in raw form so i can make a custom plot. All of the examples from AudioKit use their built in plots, but I need to use a plot I made. The input my plot is expecting is an array of Doubles, but im not very worried about typing since I can change that. I just cant get a tap to access the data working correctly. I have already looked at these:
https://groups.google.com/forum/#!searchin/audiokit/tap%7Csort:date/audiokit/V16xV7zZzPM/wuJjmhG8BwAJ
AudioKit - How to get Real Time floatChannelData from Microphone?
but these answers really just show examples from the audiokit examples which aren't helpful for what i need
Here is my attempt, which instantly crashes saying "required condition is false: [AVAEGraphNode.mm:851:CreateRecordingTap: (nullptr == Tap())]
2018-12-27 13:13:25.628188-0700"
mic.avAudioNode.installTap(onBus: 0, bufferSize:
AVAudioFrameCount(bufferSize), format: nil) { [weak self] (buffer, _) in
guard let strongSelf = self else {
AKLog("Unable to create strong reference to self")
return
}
buffer.frameLength = AVAudioFrameCount(strongSelf.bufferSize)
let offset = Int(buffer.frameCapacity - buffer.frameLength)
if let tail = buffer.floatChannelData?[0] {
print(tail)
}
}
I am working on NEHotspotHelper and trying to register but not receiving call back. Firstly,
I enabled Capability : Network Extensions
Then added this following code,
let options: [String: NSObject] = [kNEHotspotHelperOptionDisplayName : "ABC" as NSObject]
let queue: DispatchQueue = DispatchQueue(label: "com.ABC", attributes: DispatchQueue.Attributes.concurrent)
NSLog("Started wifi scanning.")
NEHotspotHelper.register(options: options, queue: queue) { (cmd: NEHotspotHelperCommand) in
NSLog("Received command: \(cmd.commandType.rawValue)")
if cmd.commandType == NEHotspotHelperCommandType.filterScanList {
//Get all available hotspots
let list: [NEHotspotNetwork] = cmd.networkList!
//Figure out the hotspot you wish to connect to
print(list)
} else if cmd.commandType == NEHotspotHelperCommandType.evaluate {
if let network = cmd.network {
//Set high confidence for the network
network.setConfidence(NEHotspotHelperConfidence.high)
let response = cmd.createResponse(NEHotspotHelperResult.success)
response.setNetwork(network)
response.deliver() //Respond back
}
} else if cmd.commandType == NEHotspotHelperCommandType.authenticate {
//Perform custom authentication and respond back with success
// if all is OK
let response = cmd.createResponse(NEHotspotHelperResult.success)
response.deliver() //Respond back
}
}
Kindly let me know if I am missing any step.
You should check the result of the register() function. If it's returning false, something is probably not configured correctly. See the full list of configuration instructions below.
Also in the screenshot you provided, you have the entitlements enabled for Hotspot Configuration, but the API you're calling is for Hotspot Helper. The two features require very different entitlements. You'll need to make sure everything is configured for Hotspot Helper to call that API. Again, see below for full details. See Hotspot Helper vs. Hotspot Configuration for more details about the differences of these similarly named APIs.
To use NEHotspotHelper:
Apply for the Network Extension entitlement.
This needs to be done at Apple's website here.
Modify your Provisioning Profile.
Go to http://developer.apple.com. Hit Edit near your profile. On the bottom where it says Entitlements, choose the one that contains the Network Extension entitlement.
Update your app's entitlements file.
The application must set com.apple.developer.networking.HotspotHelper as one of its entitlements. The value of the entitlement is a boolean set to true.
Add Background Mode
The application's Info.plist must include a UIBackgroundModes array containing network-authentication.
Note that unlike all the other background modes that are converted to human readable strings, this one will stay as network-authentication.
Call the NEHotspotHelper.register() function.
This method should be called once when the application starts up. Invoking it again will have no effect and result in false being returned.
You should make sure the function returns true. Otherwise something one of the above steps is probably not configured properly.
Understand when this callback will be called.
From the documentation, it's not entirely clear when exactly this callback will be called. For example, one might assume that NEHotspotHelper could be used to monitor for network connections. However, the callback will (only?) be called when the user navigates to the Settings app and goes to the Wi-Fi page.
Since your callback will be called only while the user in the Settings app, you should attach to the debugger and use print().
Swift Example
let targetSsid = "SFO WiFi"
let targetPassword = "12345678"
let targetAnnotation: String = "Acme Wireless"
let options: [String: NSObject] = [
kNEHotspotHelperOptionDisplayName: targetAnnotation as NSString
]
let queue = DispatchQueue(label: "com.example.test")
let isAvailable = NEHotspotHelper.register(options: options, queue: queue) { (command) in
switch command.commandType {
case .evaluate,
.filterScanList:
let originalNetworklist = command.networkList ?? []
let networkList = originalNetworklist.compactMap { network -> NEHotspotNetwork? in
print("networkName: \(network.ssid); strength: \(network.signalStrength)")
if network.ssid == targetSsid {
network.setConfidence(.high)
network.setPassword(targetPassword)
return network
}
return nil
}
let response = command.createResponse(.success)
response.setNetworkList(networkList)
response.deliver()
default:
break
}
}
assert(isAvailable)
Sources:
https://developer.apple.com/documentation/networkextension/nehotspothelper/1618965-register
https://medium.com/#prvaghela/nehotspothelper-register-an-app-as-a-hotspot-helper-cf92a6ed7b72
https://stackoverflow.com/a/39189063/35690
iam a swift beginner, i wanna code a little app for me and i have a problem with it. My app has three entities (Templates, Records and Positions), here you can see:
Datamodel
At one part of the app i can add new Records and for that Record i add some Positions (xpos and ypos).
At a part I have a tableview were i list my Records. Now i wanna click one Record in the table and i want to get all Position-Attributes linked with the particular selected Record.
With that code i can get all xpos-Positions but how can i get a single xpos? :)
guard let moc = self.managedContext else {
return
}
let fetchRequest: NSFetchRequest<Records> = Records.fetchRequest()
do {
let searchResults = try moc.fetch(fetchRequest)
let xpos = searchResults[0].positions?.mutableArrayValue(forKey: "xpos")
print(xpos)
} catch {
print("Error with request: \(error)")
}
You want to look into using NSPredicate. NSPredicate basically lets you define the conditions which the record needs to meet to be included in the results. Think of it as a filter if you will.
fetchRequest.predicate = NSPredicate(format: "uniqueID = %#", arugments:...)
I am testing ReactiveCocoa in a playground. I would like to test for the validity of a string before performing a network request.
I am not sure how to combine the textfield signal and the validation signal tho. The part of the code that is marked [??] => what is the right way to do that filter?
var textField = UITextField()
textField.text = "http://localhost:3000/users.json"
let searchStringsProducer = textField.rac_textSignal().toSignalProducer()
let searchStringValidProducer = searchStringsSignal.toSignalProducer().map{
text in
(text as! String).containsString("http")
}
// this produces a ReactiveCocoa.SignalProducer<(Optional<AnyObject>, Bool), NSError>.
let searchStringCombined = combineLatest(searchStringsProducer, searchStringValidProducer)
// turns the simple search results into a signal
let searchResults = searchStringCombined
// [??] i would like to ONLY execute on the rest of the actions if it is valid
.map{ // what do i do here before passing on to the network API }
.flatMap(FlattenStrategy.Latest) {
latestStr -> SignalProducer<[AnyObject], NSError> in
return requestJSON(latestStr, parameters: nil)
.flatMapError { error in
print("Network error occurred: \(error)")
return SignalProducer.empty
}
}.observeOn(uis)
let searchStringValidProducer = searchStringsSignal.toSignalProducer().map { text in
(text as! String).containsString("http")
}
let searchStringCombined = combineLatest(searchStringsProducer, searchStringValidProducer)
This pattern is troubling, because when searchStringsProducer sends a value, searchStringCombined will send two values -- one for the new string, and one for the new boolean. It would be neater to define this signal like this:
let searchStringCombined = searchStringsSignal.toSignalProducer().map { text in
(text, (text as! String).containsString("http"))
}
Which gives you the same result.
But you don't need to define searchStringCombined at all, unless you're using it elsewhere. You should be able to get by with a simple filter:
searchStringsSignal.toSignalProducer().filter({ text in
(text as! String).containsString("http")
}).map({
/* whatever goes here */
}).flatMap(FlattenStrategy.Latest) {
/* perform network request */
}
filter is kind of like map, in that it takes a function and returns a signal. But it only lets some values through, allowing you to only make network requests based on the valid inputs.
So this isn't a question about actually populating a table with data because I already have that working properly.
I have a page that retrieves a list of nearby users - it grabs their name, distance away and profile image. The problem is that because some profile images are bigger than others the correct profile image isn't always put alongside the corresponding name and other data.
let profileImgFile = location["profilePicture"]
profileImgFile!.getDataInBackgroundWithBlock { (data: NSData?, error: NSError?) -> Void in
if error != nil {
print("\(__FUNCTION__) - Error: (error!.localizedDescription)")
} else {
let image = UIImage(data: data!)
self.userImages.append(image!)
self.userTable.reloadData()
}
}
This is how I'm retrieving the images, they're added to an array so that the table can be populated here:
cell.nameLabel.text = "\(userData[indexPath.row])"
cell.profileImage.image = userImages[indexPath.row]
cell.distanceLabel.text = ("\(userDistance[indexPath.row])")
So, I wondered if there was any way of retrieving the images one after the other. So that the next image doesn't begin downloading until the first one has finished.
If not is there any other way of fixing this problem?
Thanks!
I think you should try setting your data async with promises.
Promises in Swift
PromiseKit
And there's a lot of other resources out there.