swift and sharedapplication - swift

first post!
i've been working with swift for a while now, but decided to move some of my code to using shared variables and objects. I'm having a fundamental issue with being able to reference appDelegate.SharedApplication().delegate. Even with a basic test application (to see if I could see any fundamental problems), I cannot get a reference to the shared variable -
// AppDelegate.swift
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let info: String = "test"
}
trying to add - "let ref = UIApplication.sharedApplication().delegate as appDelegate" in another class complains of use of undeclared type app delegate.
removing that cast allows that, but once I try to create another variable reference to the info string, complains of no member named ref.
this seems such an obvious and confusing issue that I thought it time to ask for an answer :) all i want is to be able to use the appdelegate for controlling cllocationmanager and storing the return data in a variable for a view controller class to refer to.
xcode 6.1.1
cheers

Maybe you are confusing the compiler because you are not using the proper case (upper or lower) when referring to variables or classes.
A class starts with an UpperCase letter.
Any variable starts with a lowerCase letter.
While this is not a rule for variables, it is a well-heeded convention.
Thus:
let stringFromDelegate =
(UIApplication.sharedApplication() as AppDelegate).info

Related

New error in Swift that tells me that my delegate is weak

import Cocoa
NSApplication.shared.delegate = GenerateRandomNickOnApplicationActivation()
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
This gives me the error:
Instance will be immediately deallocated because property 'delegate' is 'weak'
updated:
this worked.
var activation = GenerateRandomNickOnApplicationActivation()
NSApplication.shared.delegate = activation
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
I can't imagine that the gobal NSApplication object is valid before the call to NSApplicationMain(). One of the main job's of NSApplicationMain() (no pun intended) is to create the NSApplication object.
A better solution for pre-application startup code would be to use one of the standard application object delegate methods, like applicationWillFinishLaunching.
If you need to run code really early, define a subclass of NSApplication, register its class in your main nib file, and add your startup code to its initializer. You can also include new instance variables, etc., to hold a reference to any value(s).

How do I manually retain in Swift with ARC?

I'm using Swift 3 with ARC in an iOS app, and I want to manually retain an object.
I tried object.retain() but Xcode says that it's unavailable in ARC mode. Is there an alternative way to do this, to tell Xcode I know what I'm doing?
Long Version:
I have a LocationTracker class that registers itself as the delegate of a CLLocationManager. When the user's location changes, it updates a static variable named location. Other parts of my code that need the location access this static variable, without having or needing a reference to the LocationTracker instance.
The problem with this design is that delegates aren't retained, so the LocationTracker is deallocated by the time the CLLocationManager sends a message to it, causing a crash.
I would like to manually increment the refcount of the LocationTracker before setting it as a delegate. The object will never be deallocated anyway, since the location should be monitored as long as the app is running.
I found a workaround, which is to have a static variable 'instance' that keeps a reference to the LocationTracker. I consider this design inelegant, since I'm never going to use the 'instance' variable. Can I get rid of it and explicitly increment the refcount?
This question is not a duplicate, as was claimed, since the other question is about Objective-C, while this one is about Swift.
The solution turned out to be to re-enable retain() and release():
extension NSObjectProtocol {
/// Same as retain(), which the compiler no longer lets us call:
#discardableResult
func retainMe() -> Self {
_ = Unmanaged.passRetained(self)
return self
}
/// Same as autorelease(), which the compiler no longer lets us call.
///
/// This function does an autorelease() rather than release() to give you more flexibility.
#discardableResult
func releaseMe() -> Self {
_ = Unmanaged.passUnretained(self).autorelease()
return self
}
}
This is easily done with withExtendedLifetime(_:_:) function. From the documentation:
Evaluates a closure while ensuring that the given instance is not destroyed before the closure returns.
Cheers!

Using iRareMedia iCloudDocumentSync with Swift

Anybody using iRareMedia's iCloudDocumentSync with Swift? I used this framework successfully with Objective-C, but can't get started with Swift. In Objective C, the app initializes iCloud with the following:
[[iCloud sharedCloud] setDelegate:self]; // Set this if you plan to use the delegate
[[iCloud sharedCloud] setVerboseLogging:YES]; // We want detailed feedback about what's going on with iCloud, this is OFF by default
[[iCloud sharedCloud] setupiCloudDocumentSyncWithUbiquityContainer:nil];
I cannot figure out how to convert two of these to Swift. The class is subscribed to the iCloudDelegate protocol:
class AppDelegate: UIResponder, UIApplicationDelegate, iCloudDelegate {
For the first
[[iCloud sharedCloud] setDelegate:self];
I tried iCloud.sharedCloud().setDelegate(self) but I get a compiler error: Cannot invoke 'setDelegate' with an argument list of type '(AppDelegate)'
I've also tried iCloud.sharedCloud().delegate = self (since delegate is a property of iCloud), but I get the compiler message: Ambiguous use of 'delegate'
The second [[iCloud sharedCloud] setVerboseLogging:YES]; converts just fine with iCloud.sharedCloud().setVerboseLogging = true
The third [[iCloud sharedCloud] setupiCloudDocumentSyncWithUbiquityContainer:nil]; I've tried
iCloud.sharedCloud().setupiCloudDocumentSyncWithUbiquityContainer(nil)
which gets me: Value of type 'AnyObject' has no member 'setupiCloudDocumentSyncWithUbiquityContainer' with the error caret under the 's' of sharedCloud.
I'm baffled. I've done lots of Objective-c to Swift method conversions, so I'm not exactly new to this game, but I can't figure this out. If anyone is using iRareMedia's iCloudDocumentSync framwork with Swift, I'd appreciate any help and insights.
Thanks.
I don't know why, but setting up the iCloud delegate and initializing statements in a UIViewController allows them to all work in Swift. In the first viewcontroller in my app, I have this:
cloud = iCloud.sharedCloud() as! iCloud
cloud.delegate = self
cloud.verboseLogging = true
cloud.updateFiles()
and everything works as it's supposed to.

Why does Swift insist on this being an optional?

Caveat: I've been coding in Swift for about 2 days!
I am following along with some simple tutorials to build a status menu application. The following is a reduction of my AppDelegate.swift class:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var statusMenu: NSMenu!
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-2)
func applicationDidFinishLaunching(aNotification: NSNotification) {
let icon = NSImage(named: "StatusBarImage")
icon?.setTemplate(true)
}
}
My question is, why does Xcode insist that my icon constant be an optional (it was also OK with me forcing it to be unwrapped). The tutorial didn't show that the ? was needed, but Xcode shows me the following error if I leave it out:
Value of optional type 'NSImage' not unwrapped; did you mean to use '!' or '?'?
(I'm using Xcode 6.4, if that makes a difference.)
From Document:
Declaration:
init?(named name: String) -> NSImage
Which means by default it's initialiser is an optional.
Return Value
The NSImage object associated with the specified name or nil if no
such image was found.
Discussion
The NSImage class may cache a reference to the returned image object
for performance in some cases. However, the class holds onto cached
objects only while the object exists. If all strong references to the
image are subsequently removed, the object may be quietly removed from
the cache. Thus, if you plan to hold onto a returned image object, you
must maintain a strong reference to it like you would any Cocoa
object. You can clear an image object from the cache explicitly by
calling the object’s setName: method and specifying nil for the image
name.
That's why it is asking you did you mean to use '!' or '?'
So if you use ! that means you are unwrapping optional value and if you use ? compiler will consider it as optional.
Because image named StatusBarImage might as well not be in the assets and it would result in bad access exception.
Actually Xcode is not forcing anything : if you check the NSImage documentation you will see that the NSImage initializer is a failable initializer.
Like #FruitAddict said the whole point of those initializers is to fail gracefully (by returning an optional with a nil value) when the object could not be created. Check Apple Developer Blog
By adding ! or this ? You know explicitly that imageNamed can returned you a nil.
And Compiler just makes sure that you know about it.

About AppDelegate window in swift

here is swift default application code in Appdelecage.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
...
Can anyone tell me why create a optional var window?
why no like this as default:
var window: UIWindow = UIWindow()
that will be save lots of "?" and "!"
thx
The job of UIApplicationMain is to see that your window is nil and create and and assign a window for you. I think that's their reasoning.
But in reality, you can just change the question mark to an exclamation mark.
If you were to supply an actual window, it would also be up to you to frame it, as I do here:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch01p006customWindowInStoryboardApp/ch14p366customWindowInStoryboardApp/AppDelegate.swift
The var window declaration is to satisfy an optional declaration specified in the UIApplicationDelegate protocol. You're not required to declare it , but if you do, you are not supposed to set it with your own value. The application will set it to its own window and you're only supposed to read it. you still need to provide it as an optional (UIWindow?) because the protocol declares it as such.
Edit:
Oops, I apologize. I've been spoiled by storyboards that I forgot you can actually create the root window programmatically.