iBeacon + Parse + Swift. CLProximity - ibeacon

Need some help. I can store an ibeacon's Major Minor, UUID in Parse. But how can I story the CLProximity?
Example:
This works as I can easily convert string to Int which matches the major NSNumber type.
if clBeacon.major == beacon.objectForKey("major").integerValue
This does not work:
beacon is a PFObject and "CLProximity" is the Parse column of type String.
if beacon.objectForKey("CLProximity") as CLProximity (This doesn't work)
if beacon.objectForKey("CLProximity") as String (This doesn't work)
Any advice guys?
Thanks!

typedef NS_ENUM(NSInteger, CLProximity) {
CLProximityUnknown,
CLProximityImmediate,
CLProximityNear,
CLProximityFar
} NS_ENUM_AVAILABLE_IOS(7_0);
So, you could store CLProximity as NSInteger

You can just store the int, but if what you want to store is some kind of human readable data, I suggest doing something like this:
extension CLProximity {
var stringValue: String {
switch self {
case .unknown:
return "unknown"
case .immediate:
return "immediate"
case .near:
return "near"
case .far:
return "far"
}
}
}
So you can just do:
print("Proximity: \(proximity.stringValue)")
Works for me.

Related

How do I get text to display Coptic Calendar date SwiftUI

I am trying to use the NSCalendar initializer but i'm having trouble understanding the documentation. what I have so far is
struct SwiftUIView: View {
var body: some View {
let Date = NSCalendar.init(calendarIdentifier: .coptic)
Text("\(Date)")
}
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView()
}
}
its giving me an error saying
"Value of optional type 'NSCalendar?' must be unwrapped to a value of type 'NSCalendar'"
if someone could help me figure this out, that would be great. Thank you
The interface you want for Swift is Calendar rather than NSCalendar:
let calendar = Calendar(calendarIdentifier: .coptic)
The NSCalendar interface is from ObjC and is documented to return nil if the name of the calendar is unknown (you can pass arbitrary strings in ObjC for this parameter).
The Swift Calendar interface cannot fail because it will not allow you to create an unknown identifier.
There are many types that begin "NS" that are bridged from Objective-C. It is very common for there to be a Swift version that drops the "NS" prefix. When you see this, you should generally use the Swift version. It will generally behave in a more Swift-like way.
If your goal is to display the current date on the Coptic calendar, however, you will need more than this. A calendar represents the whole calendar, not a particular date. You will need a DateFormatter in order to create a localized string.
For example:
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.calendar = Calendar(identifier: .coptic)
dateFormatter.eraSymbols = ["BC", "AM"] // See below
print(dateFormatter.string(from: Date()))
// Baramouda 18, 1737 AM
(I believe there is a bug in Calendar such that the Coptic calendar has era symbols "ERA0" and "ERA1". I believe the correct symbols for this calendar are "BC" and "AM". You can force this by assigning them directly to the date formatter. If I'm correct that this is a bug and it impacts you, I recommend opening an Apple Feedback. See also the DateFormatter documentation for how to customize this string.)
To xTwisteDx's point, to put this in SwiftUI you want something along these lines:
struct ContentView: View {
let dateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.eraSymbols = ["BC", "AM"] // Workaround for Foundation bug
dateFormatter.calendar = Calendar(identifier: .coptic)
return dateFormatter
}()
func today() -> String {
dateFormatter.string(from: Date())
}
var body: some View {
Text(today())
.padding()
}
}
Ok so this is an issue with Optionals. Anytime you see ? or ! then you can assume that it is an optional. Essentially the reason that it is a Type?, notice the ? is because it's possible that it has returned a nil value. For example the following snippets are possible in Swift
let forceUnwrappedString: String!
let optionalString: String?
let safeString: String = "Hello World!"
print(forceUnwrappedString) //This WILL crash, the variable is nil.
print(optionalString) //This MAY crash, if the value is nil.
print(safeString) //This WON'T crash.
The way that you handle these is to check using if let or guard statements. Alternatively you can also force unwrap after checking for nil.
If Let
In this example, if optionalString is nil, the print statement WILL NOT happen. However if optionalString contains a value, it will. It's essentially a way of telling the compiler to check for nil values and only run code if it's safe.
if let safeString = optionalString {
print(safeString)
}
Guard
In this example, it works the same as an If Let with a notable difference being that the safeString is accessible at a bigger scope than the If Let also it returns if the value is not "unwrapped" so any code below it will not be called if it's not safely unwrapped.
guard let safeString = optionalString { else return }
print(safeString)
Force Unwrapping
Force unwrapping is something you should avoid however there are instances when it's acceptable. This is an example of force unwrapping. Notice that I used the ! which basically says "I know this value is not nil, use it." That is the only time you should ever use it, when you can guarantee there isn't a nil value.
let someString: String?
someString = "Hello World!"
print(someString!)
Your Problem
In the context of your issue, NSCalendar.init(calendarIdentifier: .coptic) returns an optional type or, someType? meaning it has the possibility to be nil The solution is below.
let Date = NSCalendar.init(calendarIdentifier: .coptic)
if let safeDate = Date {
Text("\(safeDate)")
} else {
//The date value was nil, do something else
}

didChangeAutomaticCapitalizationNotification not triggered

What am I doing wrong? I don't get this notification. I have this function:
#objc func onAutocorrection (_ notification: Foundation.Notification) {
Swift.print("\(notification)")
}
later in the same class I do use it as follows:
NotificationCenter.default.addObserver(
self,
selector: #selector(onAutocorrection(_:)),
name: NSSpellChecker.didChangeAutomaticCapitalizationNotification,
object: nil)
The addObserver is executed, but the function is never called even when the application is capitalising in an NSTextView.
Why? Many thanks in advance!
It looks like I misunderstood the notification. It is not meant to be triggered when automatic capitalisation happens but when the systems preference of your Mac is changing.
See the comment of ever helpful Willeke and see Notification of autocorrect
In order to get to the intended result of reacting to autocapitalisation did I implement this function in the NSTextViewDelegate:
public func textView(_ view: NSTextView, didCheckTextIn range: NSRange, types checkingTypes: NSTextCheckingTypes, options: [NSSpellChecker.OptionKey : Any] = [:], results: [NSTextCheckingResult], orthography: NSOrthography, wordCount: Int) -> [NSTextCheckingResult] {
if !range.contains(0){
return results
}
var newResult = [NSTextCheckingResult]()
for result in results {
if let textToChange = view.string[range].components(separatedBy: " ").first, let replacement = result.replacementString?.components(separatedBy: " ").first {
let firstLetterCap = textToChange.capitalizingFirstLetter()
if replacement == firstLetterCap {
continue //don't add to results
}
}
newResult.append(result)
}
return newResult
}
This function will prevent that the first character will be capitalised.
Ultimately, I check whether the capitalised version of the first word of the range that must include position "0" is equal to the first word of the replacement string. And if it is then I remove that result/suggestion from the result list.

How to set a label to parse data?

How do you set a row of parse data to be equal to label text or button text? If someone could leave me the code to do this.
The label outlet name is BookName.
I have all of the code written in swift.
Thanks,
Jeff
You can do this like so:
Create a function to fetch the object
func getPFObject() {
let query = PFQuery(className: "YourClassName")
//set your key that you're looking for here
query.findObjectsInBackgroundWithBlock { ( objects: [PFObject]?, error) -> Void in
if error == nil {
self.BookName.text = objects[0]["foo"] as! String
}
}
And then in viewDidAppear: or elsewhere
self.getPFObject()
As convention, you probably shouldn't start your variable names (like your outlets) with capital letters, it will throw people on SO off! And it's bad style too.

How to Don't Repeat Yourself with Swift 2.0 enums

I've got multiple enums with raw values, but I don't like having to say rawValue: every time I initialize one from a raw value, so I've supplied an alternative delegating initializer with no external label:
enum E1 : Int {
case One, Two
init?(_ what:Int) {
self.init(rawValue:what)
}
}
enum E2 : Int {
case One, Two
init?(_ what:Int) {
self.init(rawValue:what)
}
}
Very nice. I can say let e = E1(0) and the right thing happens.
Now I'd like to consolidate the repeated code. I was hoping that Swift 2.0 protocol extensions would allow me to do this - writing the init?(_ what:Int) initializer in one place and injecting / inheriting it in both enums. However, I haven't found a way that works. The problem is that the protocol extension doesn't know that the adopter will have an init(rawValue:) initializer, and I have not found a way to reassure it.
I suspect that this is because of the automagic way that the rawValue initializer comes into existence, and so probably nothing can be done. But perhaps someone has a suggestion.
Sounds like you're looking to extend the RawRepresentable protocol:
extension RawRepresentable {
init?(_ what: RawValue) {
self.init(rawValue: what)
}
}
Any enum with a raw type automatically conforms to RawRepresentable, therefore you haven't got to make E1 or E2 conform to any extra protocols:
enum E1: Int {
case One = 1, Two
}
enum E2: String {
case One = "1", Two = "2"
}
let e1 = E1(1) // .One
let e2 = E2("2") // .Two
I was able to get it to work, like this:
protocol P {
var rawValue : Int {get}
init?(rawValue: Int)
}
extension P {
init?(_ what:Int) {
self.init(rawValue:what)
}
}
enum E1 : Int, P {
case One, Two
}
enum E2 : Int, P {
case One, Two
}
We use the regular protocol declaration to reassure the protocol extension that our adopter will have an init?(rawValue:).
[However, there is still something very odd going on. This code compiles in one of my projects, but not in another. I think it has something to do with how other code uses the P protocol; if no other code uses the P protocol, all is well, but if other code uses the P protocol, in ways that I have not precisely determined, the code fails to compile, with a mysterious error about the enum not conforming to the protocol.]
Dunno what can be wrong. Would be nice to have isolated case. Maybe more generic version helps?
protocol BaseRaw {
typealias T
var rawValue : T { get }
init?(rawValue: T)
}
extension BaseRaw {
init?(_ value: T) {
self.init(rawValue: value)
}
}
enum E1 : Int, BaseRaw {
case One = 1
case Two = 2
}
enum E2 : String, BaseRaw {
case One = "1"
case Two = "2"
}
let e = E1(1)
let e2 = E2("2")
print(e) // Optional(E1.One)
print(e!.rawValue) // 1
print(e2) // Optional(E2.Two)
print(e2!.rawValue) // "2"

How do I compare an NSNumber to a swift enumeration value?

I'm trying to do a simple comparison of a value received via an NSNotification, and an enumeration value. I have something that works, but I can't believe that this is the right way to be doing this. Basically the solution I ended up with was converting the NSNumber to an Int, and also getting the enum value's rawValue, wrapping it in an NSNumber and then getting the integerValue of that.
Everything else I tried resulted in compiler errors about not being able to convert between Uint 8 and Int or something similar.
observer = NSNotificationCenter.defaultCenter().addObserverForName(AVAudioSessionRouteChangeNotification, object: nil, queue: mainQueue) { notification in
println(AVAudioSessionRouteChangeReason.NewDeviceAvailable.toRaw())
if let reason = notification.userInfo[AVAudioSessionRouteChangeReasonKey!] as? NSNumber {
if (reason.integerValue == NSNumber(unsignedLong:AVAudioSessionRouteChangeReason.NewDeviceAvailable.toRaw()).integerValue) {
self.headphoneJackedIn = true;
} else if (reason.integerValue == NSNumber(unsignedLong:AVAudioSessionRouteChangeReason.OldDeviceUnavailable.toRaw()).integerValue) {
self.headphoneJackedIn = false;
}
self.updateHeadphoneJackLabel()
}
}
This should work:
if reason.integerValue == Int(AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue) {
// ...
}
Remark: The AVAudioSessionRouteChangeReason enumeration uses UInt as raw value type, so
one could expect that this works without an explicit conversion:
if reason.unsignedIntegerValue == AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue {
}
However, as of Xcode 6 beta 4, NSUInteger is mapped to Swift's Int in OS X and iOS
system frameworks, which means that both integerValue and unsignedIntegerValue return an Int,
and an explicit conversion is needed in any case.
Alternatively, you could create an enumeration value from the number (as already suggested by #ColinE
in a comment) and then use switch case:
if let r = AVAudioSessionRouteChangeReason(rawValue: UInt(reason.integerValue)) {
switch r {
case .NewDeviceAvailable:
// ...
case .OldDeviceUnavailable:
// ...
default:
// ...
}
} else {
println ("Other reason")
}
For the same reason as above, an explicit UInt conversion is necessary here as well.

Resources