I develop an App in macos, and I need to access the documentDirectory:
let dialogURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
I get: file:///Users//Library/Containers/<*******.appName>/Data/Documents
But in the Library/Containers directory I don't have the <*******.appDirectory> (in my case "PR.medical") but (in my case "medical")
of course, it would be possible to hard code the name of the desired directory, but if in the future apple change anything, my app will not work properly.
Am I missing something?
Post
Replies
Boosts
Views
Activity
I test a very simple thing:
I have a Subclassed UIView as follow:
@IBDesignable
class myView: UIView {
override public init(frame: CGRect) {
super.init(frame: frame)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override open func layoutSubviews() {
super.layoutSubviews()
layer.frame.size.height = 50
layer.borderWidth = 1
layer.borderColor = UIColor.green.cgColor
}
}
To install this component in Interface Builder, I add an UIView and I change the class name in the Inspector.
When I add the UIView, the height of this view is 128. I suppose it is a default value of IB. But I want this height to be 50.
When I change the name of the class in the IB inspector, the view is correctly drawn, white a height of 50, but when I select it, the size of the selection is the size of a default UIView
Is there a mean to correct this?
I subclassed an UIView that is supposed to create it's owned constraints:
@IBDesignable class MyCtrl: UIView {
var label: UITextField!
var _internalLayout = false
public override init(frame: CGRect) {
super.init(frame: frame)
_init()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
_init()
}
open override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self._init()
self.setNeedsDisplay()
}
func _init() {
label = UITextField()
addSubview(label)
super.backgroundColor = .cyan
#if TARGET_INTERFACE_BUILDER
translatesAutoresizingMaskIntoConstraints = true
#else
translatesAutoresizingMaskIntoConstraints = false
#endif
}
override public func layoutSubviews() {
if _internalLayout {
_internalLayout = false
return
}
let theOrientation = orientation
setupConstraints(theOrientation)
super.layoutSubviews()
}
func setupConstraints(_ orientation: IosTraitClass) {
_internalLayout = true
superview?.removeConstraints(superview!.constraints)
if orientation == .CR {
label.text = "setupConstraints(.CR \(superview?.frame.size.width)"
label.sizeToFit()
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: superview , attribute: .leading , multiplier: 1, constant: 30))
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: superview, attribute: .top, multiplier: 1, constant: 100))
superview?.addConstraint( NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: (superview?.frame.size.width ?? 0)-60))
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: (superview?.frame.size.height ?? 0)-300))
} else if orientation == .RC || orientation == .CC {
label.text = "setupConstraints(.CC ou .RC \(superview?.frame.size.width)"
label.sizeToFit()
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: superview, attribute: .trailing, multiplier: 1, constant: -50))
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: superview, attribute: .top, multiplier: 1, constant: 50))
superview?.addConstraint( NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: (superview?.frame.size.width ?? 0)-100))
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: (superview?.frame.size.height ?? 0)-100))
}
}
}
In the method layoutSubviews of my component, I called orientation which is an extension of UIView:
public var orientation: IosTraitClass {
if UIScreen.main.traitCollection.horizontalSizeClass == .regular &&
UIScreen.main.traitCollection.verticalSizeClass == .compact {
return .RC
} else if UIScreen.main.traitCollection.horizontalSizeClass == .compact &&
UIScreen.main.traitCollection.verticalSizeClass == .regular {
return .CR
} else if UIScreen.main.traitCollection.horizontalSizeClass == .compact &&
UIScreen.main.traitCollection.verticalSizeClass == .compact {
return .CC
} else if UIScreen.main.traitCollection.horizontalSizeClass == .regular &&
UIScreen.main.traitCollection.verticalSizeClass == .regular {
return .RR
} else {
return .none
}
}
Finally I made a UIViewController:
class ViewController: UIViewController {
@IBOutlet weak var container: MyCtrl!
override func viewDidLoad() {
super.viewDidLoad()
setupConstraints()
}
func setupConstraints() {
container.setupConstraints(view.orientation)
}
func calculatedConstraints() -> [NSLayoutConstraint] {
return [];
var constraints = [NSLayoutConstraint]()
container.removeConstraints(container.constraints)
if view.orientation == .CR {
//constraints.append(contentsOf: container.setSize(width: (view?.frame.size.width ?? 0)-60, height: (view?.frame.size.height ?? 0)-300))
} else {
//constraints.append(contentsOf: container.setSize(width: (view?.frame.size.width ?? 0)-40, height: (view?.frame.size.height ?? 0)-100))
}
return constraints
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
container.setupConstraints(view.orientation)
super.viewWillTransition(to: size, with: coordinator)
}
}
When I run my program the constraints are well applied in landscape or portrait mode.
But when I look in the interface Builder, constraints are not applied, and I don't understand
Why
In a IOS App, I have an UITableViewCell with is own Nib and I want this UITableViewCell to react to orientation (In fact I want also this UITableViewCell to react to device: IPhone and IPad)
Suppose there are two labels in my UITableViewCell. In a portrait orientation, the second label is under the first one, in a Landscape orientation the two labels are on the same line.
First I noticed that in interface builder, if the layout of all the elements are Autoresizing Mask (and not inferred) I'm unable to put a constraint on width and heigth of the UITableViewCell and it's contentView.
Now I choose in IB: orientation Portrait, I click on Vary For Traits and I put the necessary constraints. After that, I do the same for orientation Landscape.
Then, whatever the orientation is in IB, I only see my last choice (landscape). IB doesnt react to Portrait or landscape orientation.
And it is the same when I run the App: I only see the landscape layout.
Where is my mistake? Do I have to make differnt nib files for all devices variations?
In order to display alerts, I made a simple class:
public protocol AlertDisplayer {
func displayAlert(with title: String, message: String, actions: [UIAlertAction]?, completion: (() -> Void)?)
}
extension AlertDisplayer where Self: UIViewController {
public func displayAlert(with title: String, message: String, actions: [UIAlertAction]? = nil, completion: (() -> Void)? = nil ) {
guard presentedViewController == nil else {
return
}
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
actions?.forEach { action in
alertController.addAction(action)
}
present(alertController, animated: true, completion: nil) //{
}
}
Now I make a class to this class, from another class, like this:
func passwordForgot(navigation: UINavigationController, email: String?) {
let model = loginModel()
model.rappelpwd(controller: navigation.topViewController as! AlertDisplayer, email: email!) {
result in
if result.result! {
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: {
action in
Swift.print("ok tapped")
//presentControllerLogin()
})
let title = "Attention"
let aController = navigation.topViewController as? AlertDisplayer
if aController != nil {
aController!.displayAlert(with: title , message: result.msg!, actions: [defaultAction], completion: nil)
}
}
}
}
Everyting is OK, but when I tap the OK button, the handler is never called
I have a windowController with a NSTableView and a textfield which I use to search data in my tableViewIn the controller, I intercept the keydown event and if it is a character, I want to fill the textfield with this character and give the focus to the textfieldSo I write@objc override func myKeyDown(with event: NSEvent) -> Bool {
if ctrlRch != nil {
window?.makeFirstResponder(ctrlRch)
Swift.print("firstResponder is \(window?.firstResponder)")
ctrlRch.stringValue = event.characters!
var fieldEditor = ctrlRch.currentEditor()
fieldEditor?.selectedRange = NSMakeRange(ctrlRch!.stringValue.count-1, 1)
return true
}But the caret (or the cursor) is not positionned in the textfieldWhat I missed?
I'm completely lost in encoding classes to DictionaryI have for instance the following classclass AdjectifsModel: BaseModel {
var id: Int = 0
var idmot: Int = 0
var idtypemot: Int = 0
var idracine: Int = 0
var racine: String = ""
var francais: String = ""
var msingulier: String = ""
var fsingulier: String = ""
var mpluriel: String = ""
var fpluriel: String = ""
var commentaire: String = ""
var erreur: Int = 0
var nbliens: Int = 0
enum CodingKeys: String, CodingKey {
case id
case idmot
case idtypemot
case idracine
case racine
case francais
case msingulier
case fsingulier
case mpluriel
case fpluriel
case commentaire
case erreur
case nbliens
}
}No problem to encode it with the following code:required convenience init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.init()
self.id = try container.decoder(Int.self, forKey: .id)
self.idmot = try container.decoder(Int.self, forKey: .idmot)
self.idtypemot = try container.decoder(Int.self, forKey: .idtypemot)
self.idracine = try container.decoder(Int.self, forKey: .idracine)
self.racine = try container.decoder(String.self, forKey: .racine)
self.francais = try container.decoder(String.self, forKey: .francais)
self.msingulier = try container.decoder(String.self, forKey: .msingulier)
self.fsingulier = try container.decoder(String.self, forKey: .fsingulier)
self.mpluriel = try container.decoder(String.self, forKey: .mpluriel)
self.fpluriel = try container.decoder(String.self, forKey: .fpluriel)
self.commentaire = try container.decoder(String.self, forKey: .commentaire)
self.erreur = try container.decoder(Int.self, forKey: .erreur, defaut: 0)
self.nbliens = try container.decoder(Int.self, forKey: .nbliens, defaut: 0)
}But in order to save my class, I need to transform it in a Dictionary [String: String] and I don't kown how to do itI found on the internet the following code:class DictionaryEncoder {
private let encoder = JSONEncoder()
var dateEncodingStrategy: JSONEncoder.DateEncodingStrategy {
set { encoder.dateEncodingStrategy = newValue }
get { return encoder.dateEncodingStrategy }
}
var dataEncodingStrategy: JSONEncoder.DataEncodingStrategy {
set { encoder.dataEncodingStrategy = newValue }
get { return encoder.dataEncodingStrategy }
}
var nonConformingFloatEncodingStrategy: JSONEncoder.NonConformingFloatEncodingStrategy {
set { encoder.nonConformingFloatEncodingStrategy = newValue }
get { return encoder.nonConformingFloatEncodingStrategy }
}
var keyEncodingStrategy: JSONEncoder.KeyEncodingStrategy {
set { encoder.keyEncodingStrategy = newValue }
get { return encoder.keyEncodingStrategy }
}
func encode(_ value: T) throws -> [String: Any] where T : Encodable {
let data = try encoder.encode(value)
return try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
}
}I copy it (and I must admit that I don't undestand how it works).If my class contains only strings property, the following Code works:var params = try DictionaryEncoder().encode(self)but if the properties are mixed (Strings and Int) it doesn't work
I'm complety lost with Generic typesIn a class, I've declare an array, like this:class ResponseListl: Decodable {
var moderators: [T]
}this intends to get differnt values of T thru an internet connection.No problem to fill the array in a first time, but if I want to grow this array thru a second connection, I try to make this:moderators.append (data) (data is of type T) the compiler returns me the error:Cannot invoke 'append' with an argument list of type '([T])'What is wrong with this?
I'm developing an application with a NSSplitView in the main NSWindowController which is organized like that:a menu on the left panel, which contains an outlineView with many choices and a detailView on the right panel which corresponds to the item choosen in the left panel.In the main NSWindowController, I have a toolbar with Buttons (that's the important point)Then I click on an item in the left panel, I have the following action:func outlineViewSelectionDidChange(_ notification: Notification) {
let outline = notification.object as! NSOutlineView
let item = outline.item(atRow: outline.selectedRow)
if item is MenuSocietes {
if vc != nil {
splitView.removeArrangedSubview((splitView?.subviews[1])!)
vc = nil
}
vc = societesController()
contentViewController?.presentAsModalWindow(vc)
if splitView.subviews.count > 1 {
splitView.removeArrangedSubview((splitView?.subviews[1])!)
}
splitView.addSubview(vc.view)
} if item is MenuImmeuble {
if vc != nil {
splitView.removeArrangedSubview((splitView?.subviews[1])!)
vc = nil
}
vc = immeubleController((item as! MenuImmeuble).id)
contentViewController?.presentAsModalWindow(vc)
if splitView.subviews.count > 1 {
splitView.removeArrangedSubview((splitView?.subviews[1])!)
}
splitView.addSubview(vc.view)
} else {
if vc != nil {
splitView.removeArrangedSubview((splitView?.subviews[1])!)
vc = nil
}
}
}Of course this is just a example (a little dirty, I know).societesController and immeubleController are NSViewControllers.Now I want my detailView (in the above code, societesController or immeubleController) to interact with the NSToolbar of the main NSWindowController.It would be easy to pass this toolbar as a parameter in the init code of my details NSViewController, but I'm not sure it's the finest way.I try to find, in my viewControllers (societesController and immeubleController) the ancestor, doing something like this:var _parent = presentingViewController
while _parent != nil {
Swift.print(_parent?.className)
_parent = _parent!.parent
}the first line return nil as _parent. Am I missing something?
I'm discovering SwiftUI, thinking that it is the future for developping Applications.the first thing (I'm sure it is very simple) I have difficulties is making a choice in a dynamic List.In a classic Swift I make it like thisIn my menuViewController, I have these declarations:private var choix = ["Adjectifs", "Adverbes", "Noms", "Verbes", "Prépositions", "Expressions", "Phrases", "Racines", "Quizz"]//, "test"]
private var actions = [adjectifsViewController.self, adverbesViewController.self, nomsViewController.self, verbesViewController.self, prepositionsViewController.self, expressionsViewController.self, phrasesViewController.self, associationsViewController.self, listerQuizzViewController.self] //, menu1ViewController.self]I draw a UITableView with choices ad when I click on a row of my tableView:func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if actions[indexPath.row] != "" {
let aClass = actions[indexPath.row]
let controller = aClass.loadFromNib()
self.show(controller, sender: self)
}
}Now of course I want to write this in SwiftUIfirst I have a struct like this:struct IvritMenu: Identifiable {
let id: Int
let text: String
let lien: click
}
enum click: Hashable {
case adjectifs
case adverbes
case noms
case verbes
}then in the View, I write the variable:var menu = [
IvritMenu(id: 0, text: "Adjectifs", lien: .adjectifs),
IvritMenu(id: 1, text: "Adverbes", lien: .adverbes),
IvritMenu(id:2, text: "Noms", lien: .noms),
IvritMenu(id:3, text: "Verbes", lien: .verbes)]and Finally:var body: some View {
NavigationView {
List(menu) { choix in
ListeChoix(choix: choix)
}
.navigationBarTitle(Text("Ivrit"))
}
}now the difficult part (for me) is to write ListeChoixstruct ListeChoix: View {
var choix: IvritMenu
var body: some View {
switch choix.lien {
case .adjectifs:
return Adjectifs()
defaul make itt:
return Adverbes()
}
}
}this generate an error Function declares an opaque return type, but the return statements in its body do not have matching underlying typesI think this error is caused by the return which returns different types of View, but I don't know how to make it
HiI update xcode to version 11.3 and my OS to Mojave (10.14.6)I had a macos app with NSButtons binded to a NSViewController@IBAction func Tester(_ sender: NSButton) { Swift.print("test activé") }(I made it very simple to isolate my problem)the function Tester of my viewController is never called and I can't find why