Why Xcode says that 'instance will be immediately deallocated'? - appdelegate

I'm trying to find out why am I getting the following message in Xcode:
Instance will be immediately deallocated because property 'delegate' is 'weak'
Here's a code:
import ARKit
class OtherViewController: NSObject, ARSCNViewDelegate { }
class ViewController: UIViewController, ARSCNViewDelegate {
var arView = ARSCNView(frame: .zero)
let otherVC = OtherViewController()
override func viewDidLoad() {
super.viewDidLoad()
// I'M USING ONE OF THESE
arView.delegate = self // works fine
arView.delegate = otherVC // works fine
arView.delegate = ViewController() // PRINTS WARNING
}
}
Question:
I understand that the delegate is a weak and optional:
weak var delegate: ARSCNViewDelegate? { get set }
However, why arView.delegate = self or arView.delegate = otherVC works FINE but arView.delegate = ViewController() prints a warning?

By setting arView.delegate = ViewController() you’re creating a new instance of ViewController that isn’t retained anywhere so it’s deallocated as soon as the function returns.

Related

Configuring a UIViewController outside scene(_:willConnectTo:options:) then setting it to window rootViewController doesn't work

My intention is to initialize a view controller and set it to the window rootViewController, then pass the view controller as dependency to an AppCoordinator where the app decide what to do with the view controller (replace it with an onboarding scene or login page, or even home screen if the user is already logged in.
The problem is that whenever I do that, the window doesn't seems to get back its view controller, but instead a black screen.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: windowScene)
var viewController = UIViewController()
self.window?.rootViewController = viewController
let appCoordinator = AppCoordinator(viewController: viewController)
appCoordinator.start()
window?.makeKeyAndVisible()
}
AppCoordinator.swift
import UIKit
import SwiftUI
class AppCoordinator: Coordinator {
var viewController: UIViewController
init(viewController: UIViewController) {
self.viewController = viewController
}
func start() {
let onboardingView = OnboardingView()
self.viewController = UIHostingController(rootView: onboardingView)
}
}
If I bypass the AppCoordinator and set everything in the scene delegate, the screen loads correctly:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: windowScene)
var viewController = UIViewController()
let onboardingView = OnboardingView()
self.window?.rootViewController = UIHostingController(rootView: onboardingView)
window?.makeKeyAndVisible()
}
What seems to be wrong when I pass the view controller as a dependency? Btw, I don't prefer to pass the window as dependency to the called coordinator, although this works, I don't prefer it.

manual constraints not being cuasin unwrapping issue (swift4)

My code below is causing a run time error. This works If I code a lazy var as a scrollview. But this does not work if I am just trying to add a object to the view or superview. I have connected nothing from the storyboard and do not want to.
var FIRE: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
playSound()
view.addSubview(FIRE)
FIRE.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
FIRE.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
FIRE.widthAnchor.constraint(equalToConstant: 400).isActive = true
FIRE.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
Change
var FIRE: UIImageView!
To
let FIRE = UIImageView()

CFNetwork SSLHandshake failed (-9807)

I keep receiving this error, CFNetwork SSLHandshake failed (-9807), in the debug window and have no data displayed when trying to populate a UITableViewController with Firebase data. I have tried this potential solution iOS 9 ATS and Firebase REST but still have the issue.
The code I am using is (Credit to #DavidEast)
class TableViewController1: UITableViewController {
// your firebase reference as a property
var ref: Firebase!
// your data source, you can replace this with your own model if you wish
var items = [FDataSnapshot]()
override func viewDidLoad() {
super.viewDidLoad()
// initialize the ref in viewDidLoad
ref = Firebase(url:"https://the-lighthouse-app.firebase.io/states")
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// listen for update with the .Value event
ref.observeEventType(.Value) { (snapshot: FDataSnapshot!) in
var newItems = [FDataSnapshot]()
// loop through the children and append them to the new array
for item in snapshot.children {
newItems.append(item as! FDataSnapshot)
}
// replace the old array
self.items = newItems
// reload the UITableView
self.tableView.reloadData()
}
}
}

Adding observer for KVO without pointers using Swift

In Objective-C, I would normally use something like this:
static NSString *kViewTransformChanged = #"view transform changed";
// or
static const void *kViewTransformChanged = &kViewTransformChanged;
[clearContentView addObserver:self
forKeyPath:#"transform"
options:NSKeyValueObservingOptionNew
context:&kViewTransformChanged];
I have two overloaded methods to choose from to add an observer for KVO with the only difference being the context argument:
clearContentView.addObserver(observer: NSObject?, forKeyPath: String?, options: NSKeyValueObservingOptions, context: CMutableVoidPointer)
clearContentView.addObserver(observer: NSObject?, forKeyPath: String?, options: NSKeyValueObservingOptions, kvoContext: KVOContext)
With Swift not using pointers, I'm not sure how to dereference a pointer to use the first method.
If I create my own KVOContext constant for use with the second method, I wind up with it asking for this:
let test:KVOContext = KVOContext.fromVoidContext(context: CMutableVoidPointer)
EDIT: What is the difference between CMutableVoidPointer and KVOContext? Can someone give me an example how how to use them both and when I would use one over the other?
EDIT #2: A dev at Apple just posted this to the forums: KVOContext is going away; using a global reference as your context is the way to go right now.
There is now a technique officially recommended in the documentation, which is to create a private mutable variable and use its address as the context.
(Updated for Swift 3 on 2017-01-09)
// Set up non-zero-sized storage. We don't intend to mutate this variable,
// but it needs to be `var` so we can pass its address in as UnsafeMutablePointer.
private static var myContext = 0
// NOTE: `static` is not necessary if you want it to be a global variable
observee.addObserver(self, forKeyPath: …, options: [], context: &MyClass.myContext)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
if context == &myContext {
…
}
else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
Now that KVOContext is gone in Xcode 6 beta 3, you can do the following. Define a global (i.e. not a class property) like so:
let myContext = UnsafePointer<()>()
Add an observer:
observee.addObserver(observer, forKeyPath: …, options: nil, context: myContext)
In the observer:
override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: [NSObject : AnyObject]!, context: UnsafePointer<()>) {
if context == myContext {
…
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
Swift 4 - observing contentSize change on UITableViewController popover to fix incorrect size
I had been searching for an answer to change to a block based KVO because I was getting a swiftlint warning and it took me piecing quite a few different answers together to get to the right solution. Swiftlint warning:
Block Based KVO Violation: Prefer the new block based KVO API with keypaths when using Swift 3.2 or later. (block_based_kvo).
My use case was to present a popover controller attached to a button in a Nav bar in a view controller and then resize the popover once it's showing - otherwise it would be too big and not fitting the contents of the popover. The popover itself was a UITableViewController that contained static cells, and it was displayed via a Storyboard segue with style popover.
To setup the block based observer, you need the following code inside your popover UITableViewController:
// class level variable to store the statusObserver
private var statusObserver: NSKeyValueObservation?
// Create the observer inside viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
statusObserver = tableView.observe(\UITableView.contentSize,
changeHandler: { [ weak self ] (theTableView, _) in self?.popoverPresentationController?.presentedViewController.preferredContentSize = theTableView.contentSize
})
}
// Don't forget to remove the observer when the popover is dismissed.
override func viewDidDisappear(_ animated: Bool) {
if let observer = statusObserver {
observer.invalidate()
statusObserver = nil
}
super.viewDidDisappear(animated)
}
I didn't need the previous value when the observer was triggered, so left out the options: [.new, .old] when creating the observer.
Update for Swift 4
Context is not required for block-based observer function and existing #keyPath() syntax is replaced with smart keypath to achieve swift type safety.
class EventOvserverDemo {
var statusObserver:NSKeyValueObservation?
var objectToObserve:UIView?
func registerAddObserver() -> Void {
statusObserver = objectToObserve?.observe(\UIView.tag, options: [.new, .old], changeHandler: {[weak self] (player, change) in
if let tag = change.newValue {
// observed changed value and do the task here on change.
}
})
}
func unregisterObserver() -> Void {
if let sObserver = statusObserver {
sObserver.invalidate()
statusObserver = nil
}
}
}
Complete example using Swift:
//
// AppDelegate.swift
// Photos-MediaFramework-swift
//
// Created by Phurg on 11/11/16.
//
// Displays URLs for all photos in Photos Library
//
// #see http://stackoverflow.com/questions/30144547/programmatic-access-to-the-photos-library-on-mac-os-x-photokit-photos-framewo
//
import Cocoa
import MediaLibrary
// For KVO: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID12
private var mediaLibraryLoaded = 1
private var rootMediaGroupLoaded = 2
private var mediaObjectsLoaded = 3
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
var mediaLibrary : MLMediaLibrary!
var allPhotosAlbum : MLMediaGroup!
func applicationDidFinishLaunching(_ aNotification: Notification) {
NSLog("applicationDidFinishLaunching:");
let options:[String:Any] = [
MLMediaLoadSourceTypesKey: MLMediaSourceType.image.rawValue, // Can't be Swift enum
MLMediaLoadIncludeSourcesKey: [MLMediaSourcePhotosIdentifier], // Array
]
self.mediaLibrary = MLMediaLibrary(options:options)
NSLog("applicationDidFinishLaunching: mediaLibrary=%#", self.mediaLibrary);
self.mediaLibrary.addObserver(self, forKeyPath:"mediaSources", options:[], context:&mediaLibraryLoaded)
NSLog("applicationDidFinishLaunching: added mediaSources observer");
// Force load
self.mediaLibrary.mediaSources?[MLMediaSourcePhotosIdentifier]
NSLog("applicationDidFinishLaunching: done");
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
NSLog("observeValue: keyPath=%#", keyPath!)
let mediaSource:MLMediaSource = self.mediaLibrary.mediaSources![MLMediaSourcePhotosIdentifier]!
if (context == &mediaLibraryLoaded) {
NSLog("observeValue: mediaLibraryLoaded")
mediaSource.addObserver(self, forKeyPath:"rootMediaGroup", options:[], context:&rootMediaGroupLoaded)
// Force load
mediaSource.rootMediaGroup
} else if (context == &rootMediaGroupLoaded) {
NSLog("observeValue: rootMediaGroupLoaded")
let albums:MLMediaGroup = mediaSource.mediaGroup(forIdentifier:"TopLevelAlbums")!
for album in albums.childGroups! {
let albumIdentifier:String = album.attributes["identifier"] as! String
if (albumIdentifier == "allPhotosAlbum") {
self.allPhotosAlbum = album
album.addObserver(self, forKeyPath:"mediaObjects", options:[], context:&mediaObjectsLoaded)
// Force load
album.mediaObjects
}
}
} else if (context == &mediaObjectsLoaded) {
NSLog("observeValue: mediaObjectsLoaded")
let mediaObjects:[MLMediaObject] = self.allPhotosAlbum.mediaObjects!
for mediaObject in mediaObjects {
let url:URL? = mediaObject.url
// URL does not extend NSObject, so can't be passed to NSLog; use string interpolation
NSLog("%#", "\(url)")
}
}
}
}

how to capture camera with UIImagePickerController in swift?

I'm trying use UIImagePickerController in swift but isn't work...
my ViewController:
class ViewController: UIViewController {
#IBOutlet var imag : UIView = nil
#IBAction func capture(sender : UIButton) {
println("Button capture")
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)
{
var imag = UIImagePickerController()
imag.delegate = self
imag.sourceType = UIImagePickerControllerSourceType.Camera;
imag.mediaTypes = kUTTypeImage
imag.allowsEditing = false
self.presentViewController(imag, animated: true, completion: nil)
}
}
}
I have errors in following line of code
imag.delegate = self
(Type'ViewControlles does confoorm to protocol 'UIImagePickerControllerDelegate')
imagePicker.mediaTypes = kUTTypeImage
(use of unresolved identifier kUTTypeImage)
I have read that kUTTypeImage cant use in swift.but don't know, i am using bad this functions. Any help?
Thanks!!
You should also import MobileCoreServices in the controller:
import MobileCoreServices
and then put the type inside square brackets like this:
image.mediaTypes = [kUTTypeImage]
Swift 2.0 and Higher
image.mediaTypes = [kUTTypeImage as String]
Swift 2.0
In Swift 2.0 (Xcode 7), you need to explicitly cast kUTTypeImage (a CFString) to String:
picker.mediaTypes = [kUTTypeImage as String]
And you still need to import Mobile Core Services for this symbol to be defined:
import MobileCoreServices
That said, the default value of mediaTypes is [kUTTypeImage] anyway, so you don't need to set it if that's what you want.
also you should add UINavigationControllerDelegate to the protocols list of the ViewController
and one of the optional delegate functions (if you a planing to get a picture)
This is the working code for your issue:
import UIKit
import MobileCoreServices
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!){
println("i've got an image");
}
#IBAction func capture(sender : UIButton) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera){
println("Button capture")
var imag = UIImagePickerController()
imag.delegate = self
imag.sourceType = UIImagePickerControllerSourceType.Camera;
imag.mediaTypes = [kUTTypeImage]
imag.allowsEditing = false
self.presentViewController(imag, animated: true, completion: nil)
}
}
}
From Your Piece of code its very clear that you are making mistakes at two place one is setting delegate and second is setting Media type imag.mediaTypes = kUTTypeImage
First One:If you look into the delegate definition of UIImagePickerController it requires to confirm two protocol UINavigationControllerDelegate and UIImagePickerControllerDelegate so you have to adopt these two protocols in your viewcontroller class like as
class ViewController: UIViewController,UINavigationControllerDelegate, UIImagePickerControllerDelegate
second error:If you look into the definition part of mediaTypes it clearly requires array of media types to passed so do like this
imag.mediaTypes = [kUTTypeImage]
Apart from this, I have written a very descent class for the same task
It is easy to understand and integrate.
Here you go
//Declare property
var imagePicker:ImageVideoPicker?
//Call below line of code properly, it will return an image
self.imagePicker = ImageVideoPicker(frame: self.view.frame, superVC: self) { (capturedImage) -> Void in
if let captureImage = capturedImage{
//you did it.....
}
}
You have to conform to the delegate like this
class ViewController: UIViewController, UIImagePickerControllerDelegate
Per documentation, by default the media types is set to image so you can go ahead and delete that line since you are only setting it to image.
Do not forget to implement the protocol methods which are outlined in the documentation:
documentation
Try this
import UIKit
import AVFoundation
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
var imagePicker: UIImagePickerController!
#IBOutlet weak var ImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func takeImage(sender: AnyObject) {
imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .Camera
presentViewController(imagePicker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
imagePicker.dismissViewControllerAnimated(true, completion: nil)
ImageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
}
}
swift 1.2 syntax:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
let image = info[UIImagePickerControllerOriginalImage]
}

Resources