Swift crashes in CFRelease when leaving scope - ios

I've just thrown myself into iOS development and I'm current getting a runtime error in the function CFRelease just at the end of the queryServer function (I put a comment on the line that get's highlighted) and I don't have an error if I comment out the function call to extractIPFromQuery.
The code below is taking the name of a server and returning a list of ip addresses to that server.
func extractIPFromQuery(query: NSArray) -> [String] {
var addresses = [String]()
for x in 0...query.count - 1{
let adr = "\(query[x])"
let adrStart = adr.startIndex.advancedBy(10)
let adrEnd = adr.startIndex.advancedBy(18)
let address = adr.substringWithRange(Range<String.Index>(start: adrStart, end: adrEnd))
var final = ""
// Convert the hex version of the address into
// a human readable version
for seg in 0...3{
let start = address.startIndex.advancedBy(seg * 2)
let end = address.startIndex.advancedBy((seg * 2) + 2)
let hexRange = Range<String.Index>(start: start, end: end)
let hexPair = address.substringWithRange(hexRange)
final += "\(UInt8(strtoul(hexPair, nil, 16)))"
if(seg != 3){
final += "."
}
}
addresses.append(final)
}
return addresses;
}
func queryServer(hostName: String) -> [String]{
var ips = [String]()
if hostName != "\0" {
let hostRef = CFHostCreateWithName(kCFAllocatorDefault, hostName).takeRetainedValue()
while(CFHostStartInfoResolution(hostRef, CFHostInfoType.Addresses, nil) == false){}
ips += extractIPFromQuery(CFHostGetAddressing(hostRef, nil)!.takeRetainedValue() as NSArray)
} // Code breaks here
return ips
}

CFHostGetAddressing does not have "Create" or "Copy" in its name,
which means that it does not return a (+1) retained object.
Therefore you have to use takeUnretainedValue() to get the
value of the unmanaged reference.
For more information about these naming conventions, see "The Create Rule" and "The Get Rule"
in Ownership Policy
in the "Memory Management Programming Guide for Core Foundation".

You are taking ownership of the array returned by CFHostGetAddressing, which means ARC will insert a release call to balance the retain call that thinks needs to be balanced, when in fact it doesn't need to do this. You should be using takeUnretainedValue() instead of takeRetainedValue() as the name semantics of CFHostGetAddressing don't imply you are required to take ownership of the result.
At a basic level, the difference between takeRetainedValue() and takeUnretainedValue() is that the former will instruct ARC to insert a release call when the variable get's out of scope, while the latter one will not. At a semantical level, the former one tells that you want, or need to take ownership of the variable, usually meaning that there's an unbalanced retain call on that object, which ARC will balance.

Related

RxSwift - behavior of subscribe(observer:)

I'm confused about behavior of subscribe method in RxSwift.
This is sample code.
let observer1 = PublishSubject<String>()
let observer2 = PublishSubject<String?>()
let observable1 = Observable.just("")
let observable2 = observable1.map { $0 }
_ = observable1.subscribe(observer1) // #1. OK
_ = observable1.subscribe(observer2) // #2. Error
_ = observable2.subscribe(observer2) // #3. Error
_ = observable1.map{ $0 }.subscribe(observer2) // #4. OK
I understand that #2 and #3 get an error.
Because the observer is a nullable-string type, it is strictly different from the type that the observable holds.
But I can not understand #4.
If directly subscribe of the mapped observable, it did not get an error.
As shown in #3, the return value of the mapped observable1 was Observable.
I look forward to reply.
This is because .map { $0 } actually returns a Observable<String?> in the fourth case!
Ww can cast the return value to a Observable<String>:
_ = (observable1.map{ $0 } as Observable<String>).subscribe(observer2)
It stops working! This implies that the value returned by map without the cast must be different. And there's only one possibility - Observable<String?>. $0 can't be implicitly convertible to other types.
The compiler sees that you are calling subscribe(Observable<String?>) and infers the return type of map to be Observable<String?> because only then can subscribe be called successfully.
But if you don't give the compiler enough context to figure out the type that map should return, like you did in the let observable2 = ... line, then the compiler thinks you want a Observable<String>.
Basically, the compiler is being smart.

Swift memory address of outside instance of inout parameter same as copied instance

This is my playground code.
import Foundation
func printAddress<T>(anyObj: T,message: String = "") {
var copy = anyObj
withUnsafePointer(to: &copy) {
print("\(message) value \(copy) has memory address of: \($0)")
}
}
class Account {
var balance: Int = 0
init(balance: Int) {
self.balance = balance
}
}
func deposit(amount: Int, into account: inout Account) {
account.balance += amount
printAddress(anyObj: account, message: "After deposit") //0x00007fff569ba188
printAddress(anyObj: acct,message: "Address of acct within the deposit free function") //0x00007fff59eb6188
//What makes both memory addresses are same inside the fucntion?
}
func verify(account: Account) -> Bool{
printAddress(anyObj: acct,message: "Address of acct within the verify function") //0x00007fff5a39a188
//Again surprisingly same as address used in deposit function copied account var. Optimization?
return account.balance > 0
}
var acct = Account(balance: 10)
printAddress(anyObj: acct,message:"Before deposit 20") // Print 0x00007fff518751f8
deposit(amount: 20, into: &acct)
verify(account: acct)
printAddress(anyObj: acct,message:"After and deposit and verify completed") //// Print 0x00007fff518751f8
I have 2 observations that are not clear to me.
Why it prints the same memory address for account(Copied instance) and acct(The original acct)
When I print the memory address inside verify method call. Why it again same as the address used in previous method call. Is it something due to compiler optimisation.
What's happening is that you're always printing the address of the copy variable inside the printAddress() function. You're not printing the address of the argument you passed in, even though that is what you intended.
The address of the copy variable is always some constant fixed offset past the stack pointer that is current when printAddress() is entered, but the stack pointer changes depending on how deeply nested your code is when printAddress() is called.
To see yet another value, make a function foo() that calls printAddress(), and call foo() from verify().
Again, it's always the memory address of the copy variable you see at the point in time that print() is called.
If you want to print the memory address of the thing passed to printAddress(), you'll need to get rid of the temporary:
func printAddress<T>(anyObj: inout T, message: String = "") {
withUnsafePointer(to: &anyObj) {
print("\(message) value \(anyObj) has memory address of: \($0)")
}
}
Now call:
printAddress(anyObj: &acct, message: "message")
From anywhere and you'll see the same value.

Turn a string into a variable

Hello I have a for in loop where elements is the variable being changed and in this case "elements" is a string but there is a corresponding variable out side of the for in loop that has the same name as the string called elements. So what I mean is out side there is a Var time = [some,text,words] and theres a for in loop that calls a STRING named "time" and I would like to know how to convert the string in the for in loop into the variable by some how taking off the "'s (not that simple I know) without specifically saying "time"(the variable) but instead converting the "elements"(which is the string 'time') string into the variable. I hope I was clear enough if I'm not making sense I'll try again.
You cannot refer to local variables dynamically by their names in Swift. This would break a lot of compiler optimizations as well as type safety if you could.
You can refer to object properties by their names if the class conforms to key-value coding. For example:
class X : NSObject {
let time = ["some", "text", "words"]
func readWordsFromProp(name: String) -> String {
guard let list = self.valueForKey(name) as? [String] else {
return ""
}
var result = ""
for word in list {
result += word
}
return result
}
}
let x = X()
print(x.readWordsFromProp("time"))
In general, there are better ways to do things in Swift using closures that don't rely on fragile name-matching. But KVC can be a very powerful tool

Assigning Closure to variable in Swift causes 'variable used before being initialized'

I have a problem with a closure that is meant to be created and then being executed within another function over the range of the 2D pixel raster of an image where it shall basically called like this:
filter(i,j) and return a value based on its arguments.
I thought this code should work but it complains that the closure variable I have created is not initialized. I guess that means that I did not gave it arguments, but I wont within this function as the data is known to the closure at the time when it interacts with the image. How can I setup a closure which does not care about initialization?
Thank you in advance :)
func processFilter(type:FilterType){
var x = 0
var y = 0
//create cloure
var closure:(i:Int, j:Int)->Int
if(type == FilterType.MyFilter) {
x = 1024
y = 2048
func filter(i:Int, j:Int)->Int {
return i*j*x*y*4096
}
//compiler does not complain here...
closure = filter
}
//other if statements with different closure definitions follow...
//This call throws error: variable used before being initialized
let image = filterImage(closure)
}
You use the variable closure before the compiler is certain that it is initialized. You can solve this in 2 ways, depending on what you need:
Add an else-clause to your if and set closure to a default closure.
Make closure optional by defining it as var closure: ((i: Int, j: Int) -> Int)? and then you can check if it is optional before using it by using closure?(i, j) or if let filter = closure { filter(i, j)}.
Also, try to use better variable names such as filterClosure. closure on its own doesn't really say much.
The problem is that you define your closure as:
var closure:(i:Int, j:Int)->Int
Then you initialize it only if you enter the if
If not, that var is not initialized, hence the compiler warning
Possible solution:
func processFilter(type:FilterType){
var x = 0
var y = 0
//create cloure
var filterClosure:((i:Int, j:Int)->Int)?
if(type == FilterType.MyFilter) {
x = 1024
y = 2048
func filter(i:Int, j:Int)->Int {
return i*j*x*y*4096
}
//compiler does not complain here...
filterClosure = filter
}
//other if statements with different closure definitions follow...
if let closure = filterClosure {
let image = filterImage(closure)
}
}
Your closure is only initialized if the code enters your if block (i.e. if type == FilterType.MyFilter). In the other case it is left uninitialized.

Assigning let variable in fallible initializer swift 1.2

I have a struct with a fallible initializer, not an instance method, but an initializer. After updating to 1.2, when I try to assign a let property inside the initializer, I receive the following error Cannot assign to 'aspectRatio' in self. My code below:
import Foundation
public struct MediaItem
{
public let url: NSURL!
public let aspectRatio: Double
public var description: String { return (url.absoluteString ?? "no url") + " (aspect ratio = \(aspectRatio))" }
// MARK: - Private Implementation
init?(data: NSDictionary?) {
var valid = false
if let urlString = data?.valueForKeyPath(TwitterKey.MediaURL) as? NSString {
if let url = NSURL(string: urlString as String) {
self.url = url
let h = data?.valueForKeyPath(TwitterKey.Height) as? NSNumber
let w = data?.valueForKeyPath(TwitterKey.Width) as? NSNumber
if h != nil && w != nil && h?.doubleValue != 0 {
aspectRatio = w!.doubleValue / h!.doubleValue
valid = true
}
}
}
if !valid {
return nil
}
}
struct TwitterKey {
static let MediaURL = "media_url_https"
static let Width = "sizes.small.w"
static let Height = "sizes.small.h"
}
}
My question is what do I do to fix this?
Swift 1.2 has closed a loophole having to do with let properties:
The new rule is that a let constant must be initialized before use (like a var), and that it may only be initialized, not reassigned or mutated after initialization.
That rule is exactly what you are trying to violate. aspectRatio is a let property and you have already given it a value in its declaration:
public let aspectRatio: Double = 0
So before we ever get to the initializer, aspectRatio has its initial value — 0. And that is the only value it can ever have. The new rule means that you can never assign to aspectRatio ever again, not even in an initializer.
The solution is (and this was always the right way): assign it no value in its declaration:
public let aspectRatio: Double
Now, in the initializer, either assign it 0 or assign it w!.doubleValue / h!.doubleValue. In other words, take care of every possibility in the initializer, once. That will be the only time, one way or another, that you get to assign aspectRatio a value.
If you think about it, you'll realize that this is a much more sensible and consistent approach; previously, you were sort of prevaricating on the meaning of let, and the new rule has stopped you, rightly, from doing that.
In your rewrite of the code, you are failing to initialize all properties in the situation where you intend to bail out and return nil. I know it may seem counterintuitive, but you cannot do that. You must initialize all properties even if you intend to bail out. I discuss this very clearly in my book:
A failable class initializer cannot say return nil until after it has completed all of its own initialization duties. Thus, for example, a failable subclass designated initializer must see to it that all the subclass’s properties are initialized and must call super.init(...) before it can say return nil. (There is a certain delicious irony here: before it can tear the instance down, the initializer must finish building the instance up.)
EDIT: Please note that starting in Swift 2.2, this requirement will be lifted. It will be legal to return nil before initializing properties. This will put class initializers on a par with struct initializers, where this was already legal.

Resources