Swift: Why class method has return type AnyObject? - swift

NSDate.distantFuture() is documented to return an object of type NSDate.
So then, why does it have a return type of AnyObject, instead of NSDate?

In Objective-C distantFuture returns an id, not NSDate. Automatic Swift conversion makes this an AnyObject. When the class will be reviewed by Apple they will probably switch that to NSDate.
NSDate's distantFuture is actually from the distant past (at least Mac OS X 10.0, probably even before that). At this time many factory methods returned id because there was no instancetype. It was just to make it easier to call a subclasses method on the returned object.

This is actually documented as returning AnyObject.
returns nil if an event specified in the event mask does not happen before the specified date.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/#//apple_ref/occ/clm/NSDate/distantFuture**
distantFuture
Creates and returns an NSDate object representing a date in the distant future.
Declaration
SWIFT
class func distantFuture() -> AnyObject
OBJECTIVE-C
+ (id)distantFuture
Return Value
An NSDate object representing a date in the distant future (in terms of centuries).
Discussion
You can pass this value when an NSDate object is required to have the date argument essentially ignored. For example, the NSWindow method nextEventMatchingMask:untilDate:inMode:dequeue: returns nil if an event specified in the event mask does not happen before the specified date. You can use the object returned by distantFuture as the date argument to wait indefinitely for the event to occur.
myEvent = [myWindow nextEventMatchingMask:myEventMask
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
Import Statement
import Foundation
Availability
Available in OS X v10.0 and later.

Related

Understanding UnsafeMutablePointers and how to deal with them

Could anyone please explain or give a link to a good guide on UnsafeMutablePointers? I can't freaking understand how they work and how to modify them.
Here's an example.
I am migrating my custom video player to Swift from Objective-C.
In Objective-C I create MTAudioProcessingTapRef using a callbacks structure:
MTAudioProcessingTapCallbacks callbacks;
callbacks.clientInfo = (__bridge void *)(self);
callbacks.init = initTap;
// Init other fields of callbacks
MTAudioProcessingTapCreate(kCFAllocatorDefault, &callbacks, kMTAudioProcessingTapCreationFlag_PostEffects, &tap);
Here I cast retainable MyClass pointer to void pointer to use it as clientInfo later.
(__bridge T) op casts the operand to the destination type T. If T is a
non-retainable pointer type, then op must have a retainable object
pointer type.
Then tap gets initialized:
void initTap(MTAudioProcessingTapRef tap, void *clientInfo, void **tapStorageOut)
{
*tapStorageOut = clientInfo;
}
Here I pass a pointer to self into tapStorageOut to grab self inside tap's callback function.
And then processing is performed:
void processTap(MTAudioProcessingTapRef tap, CMItemCount numberFrames, MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut,
CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut)
{
MyClass *self = (__bridge MyClass *) MTAudioProcessingTapGetStorage(tap);
MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, flagsOut, NULL, numberFramesOut);
}
Now I have a few issues here.
I did found how to cast types into other types. Here are the functions:
func bridge<type : AnyObject>(object : type) -> UnsafeRawPointer
{
let unmanagedObject : Unmanaged = Unmanaged.passUnretained(object)
let unsafeMutableRawObject : UnsafeMutableRawPointer = unmanagedObject.toOpaque()
return UnsafeRawPointer(unsafeMutableRawObject)
}
func bridge<type : AnyObject>(pointer : UnsafeRawPointer) -> type
{
let unmanagedObject : Unmanaged<type> = Unmanaged<type>.fromOpaque(pointer)
let object : type = unmanagedObject.takeUnretainedValue()
return object
}
but I have zero understanding of what all of these letters do. Some explanation of this by one of you guys would be awesome.
Let's look at initTap function. Here I have a pointer A (tapStorageOut) that references a pointer B that references some data. I change pointer B to pointer C, which is my clientInfo. Clear as a sunny day.
Now, in Swift tapStorageOut is UnsafeMutablePointer now, whatever that thing is. And I have zero clue about how to deal with it.
In Objective-C when I process data I have a bufferListInOut variable which is a pointer to AudioBufferList structure.
In Swift however it has UnsafeMutablePointer type. So again, not understanding how UnsafeMutablePointers work prevents me from grabbing the data.
The main use of a pointer in Swift is working with C API and such. For the most part you should use reference semantics instead of pointers in Swift. That means using a class, when you pass a class instance around it automatically passes a reference instead of making a copy. Thus, it saves resources and any changes you make to a reference to the instance are reflected everywhere it is referenced. A Swift class is generally instantiated on the heap.
When you convert Objective-C to Swift pointers to objects are generally treated as references to those objects. Internally, a Swift reference is pretty much semantic sugar for a pointer.
Swift structures, on the other hand, have value semantics. They are generally instantiated on the stack and when you pass them around they are copied rather than passing a reference. The same goes when you mutate them, a new instance is created with the new values and it is swapped for the old instance. There are some tricks done where a struct will wrap a block of memory and hold a pointer to that memory. Thus a struct may have some reference semantics internally but try to avoid breaking the expectation of a struct's value being copied when it's passed around.
Some good reading:
Fundamentals of Callbacks for Swift Developers
Thinking in Swift, Part 3: Struct vs. Class
Lazy Initialization with Swift
I'd read these and take a good, hard look at your architecture before trying to use stuff like UnsafeMutablePointer. Yes, they are useful in some circumstances but they can be a pain to work with and are not necessary for most pure Swift tasks. Especially in a Swift API!

Why does the Swift identity operator "===" return true for NSNumbers?

the operator "===" should compare class references to determine if both sides are referring same object:
var objectA : NSNumber = 1
var objectB : NSNumber = 1
print(objectA === objectB)
// return true,
so my question is NSNumber wrapped the object into the same object, how is the back-end logic of doing so.
NSNumber is one of a small handful of classes which can sometimes be represented as tagged pointers (at least on Apple platforms; I don't think this applies to the open-source version of (Core)Foundation).
Basically, this means that rather than a pointer to an actual instance of a class located elsewhere in memory, the NSNumber stores its value (in this case 1) directly inside the pointer. You can see this for yourself:
import Foundation
let x: NSNumber = 1
let y: NSNumber = 2
// Tagged pointers: the number is stored inside the pointer representation.
print(Unmanaged.passUnretained(x).toOpaque()) // 0x0000000000000137
print(Unmanaged.passUnretained(y).toOpaque()) // 0x0000000000000237
class C {}
let c = C()
// Not a tagged pointer; just a regular pointer to allocated memory.
print(Unmanaged.passUnretained(c).toOpaque()) // 0x00007fb32276daa0
The same optimizations can apply to NSString and other types too. For more details, read Mike Ash's excellent in-depth blog posts:
Friday Q&A 2012-07-27: Let's Build Tagged Pointers
Friday Q&A 2015-07-31: Tagged Pointer Strings
Don't rely on this, however. It's just an implementation detail, and not all NSNumbers may be represented this way. The correct way to compare them for equality is ==.

Why is `as Date` required for `timeIntervalSince()` with two `NSDate` objects?

I have an NSManagedObject object with:
#NSManaged public var timestamp: NSDate
I needed the time interval between two of these, so I implemented:
let interval = next.timestamp.timeIntervalSince(current.timestamp)
Why does this result in the following error?
'NSDate' is not implicitly convertible to 'Date'; did you mean to use
'as' to explicitly convert?
I'm surprised because both next and current are of type NSDate, and timeIntervalSince() is an NSDate method.
It's easily fixed by following the suggestion in the error, but I'd like to understand what going on here:
let interval = next.timestamp.timeIntervalSince(current.timestamp as Date)
In case it matters, this is on Swift 3.0.
Referring to NSDate Apple Documentation:
The Swift overlay to the Foundation framework provides the Date
structure, which bridges to the NSDate class. The Date value type
offers the same functionality as the NSDate reference type, and the
two can be used interchangeably in Swift code that interacts with
Objective-C APIs. This behavior is similar to how Swift bridges
standard string, numeric, and collection types to their corresponding
Foundation classes.
If you check timeIntervalSince method signature, it is func timeIntervalSince(_ anotherDate: Date) -> TimeInterval, note that anotherDate date type is Date (not NSDate anymore).
For more information about new value types, check this proposal of mutability and foundation value types, there is a bunch of new value types such as: NSData, NSMutableData -> Data, NSIndexPath -> IndexPath, NSNotification -> Notification...

NSCalendar.startOfDayForDate(date:) equivalent for iOS 7 with non-optional return type

Is it possible to change an NSDate object so that the result is equivalent to NSCalendar.startOfDayForDate(date:)? That method is only available to iOS 8 and newer, but I am looking for something that works on iOS 7.
I have looked at two methods:
NSCalendar.dateFromComponents(comps:) as described here: NSDate beginning of day and end of day. For instance, like this:
class func startOfDay(date: NSDate, calendar: NSCalendar) -> NSDate {
if #available(iOS 8, *) {
return calendar.startOfDayForDate(date)
} else {
let dateComponents = calendar.components([.Year, .Month, .Day], fromDate: date)
return calendar.dateFromComponents(dateComponents)!
}
}
NSDateFormatter.dateFromString(string:) by way of
stringFromDate(date:), i.e. converting the NSDate object into a string without the time, then converting it back into an NSDate object.
The problem with both methods is that they return an optional NSDate. I am reluctant to unwrap this implicitly and I’d rather avoid changing the return type of the method within which these methods are called.
I think the calendar.components() method returns an optional, because you can theoretically enter components that do not create valid date, like 2000-02-30. If, as in your case, the components already come from a valid date, I would not be reluctant to implicitly unwrap the optional.

Is there a correct way to determine that an NSNumber is derived from a Bool using Swift?

An NSNumber containing a Bool is easily confused with other types that can be wrapped in the NSNumber class:
NSNumber(bool:true).boolValue // true
NSNumber(integer: 1).boolValue // true
NSNumber(integer: 1) as? Bool // true
NSNumber(bool:true) as? Int // 1
NSNumber(bool:true).isEqualToNumber(1) // true
NSNumber(integer: 1).isEqualToNumber(true) // true
However, information about its original type is retained, as we can see here:
NSNumber(bool:true).objCType.memory == 99 // true
NSNumber(bool:true).dynamicType.className() == "__NSCFBoolean" // true
NSNumber(bool:true).isEqualToValue(true) || NSNumber(bool:true).isEqualToValue(false) //true
The question is: which of these approaches is the best (and/or safest) approach to determining when a Bool has been wrapped within an NSNumber rather than something else? Are all equally valid? Or, is there another, better solution?
You can ask the same question for Objective-C, and here is an answer in Objective-C - which you can call from, or translate into, Swift.
NSNumber is toll-free bridged to CFNumberRef, which is another way of saying an NSNumber object is in fact a CFNumber one (and vice-versa). Now CFNumberRef has a specific type for booleans, CFBooleanRef, and this is used when creating a boolean CFNumberRef aka NSNumber *... So all you need to do is check whether your NSNumber * is an instance of CFBooleanRef:
- (BOOL) isBoolNumber:(NSNumber *)num
{
CFTypeID boolID = CFBooleanGetTypeID(); // the type ID of CFBoolean
CFTypeID numID = CFGetTypeID((__bridge CFTypeRef)(num)); // the type ID of num
return numID == boolID;
}
Note: You may notice that NSNumber/CFNumber objects created from booleans are actually pre-defined constant objects; one for YES, one for NO. You may be tempted to rely on this for identification. However, though is currently appears to be true, and is shown in Apple's source code, to our knowledge it is not documented so should not be relied upon.
HTH
Addendum
Swift code translation (by GoodbyeStackOverflow):
func isBoolNumber(num:NSNumber) -> Bool
{
let boolID = CFBooleanGetTypeID() // the type ID of CFBoolean
let numID = CFGetTypeID(num) // the type ID of num
return numID == boolID
}
The first one is the correct one.
NSNumber is an Objective-C class. It is built for Objective-C. It stores the type using the type encodings of Objective-C. So in Objctive-C the best solution would be:
number.objCType[0] == #encoding(BOOL)[0] // or string compare, what is not necessary here
This ensures that a change of the type encoding will work after re-compile.
AFAIK you do not have #encoding() in Swift. So you have to use a literal. However, this will not break, because #encoding() is replaced at compile time and changing the encodings would break with compiled code. Unlikely.
The second approach uses a internal identifier. This is likely subject of change.
I think the third approach will have false positives.
Don't rely on the class name as it likely belongs to a class cluster, and it is an implementation detail (and therefore subject to change).
Unfortunately, the Objective-C BOOL type was originally a just typedef for a signed char in C, which is always encoded as c (this is the 99 value you are seeing, since c in ASCII is 99).
In modern Objective-C, I believe the BOOL type is an actual Boolean type (i.e. no longer just a typedef for signed char) but for compatibility, it still encodes as c when given to #encode().
So, there's no way to tell whether the 99 originally referred to a signed char or a BOOL, as far as NSNumber is concerned they are the same.
Maybe if you explain why you need to know whether the NSNumber was originally a BOOL, there may be a better solution.