{"id":24143634,"url":"https://github.com/pgreze/hackingwithswift","last_synced_at":"2026-05-11T08:38:01.252Z","repository":{"id":112007243,"uuid":"383674861","full_name":"pgreze/hackingWithSwift","owner":"pgreze","description":"My code from hackingwithswift reading","archived":false,"fork":false,"pushed_at":"2021-07-12T05:43:29.000Z","size":1226,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-12T05:28:43.139Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.hackingwithswift.com/read","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pgreze.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-07T04:40:14.000Z","updated_at":"2021-07-12T05:43:31.000Z","dependencies_parsed_at":null,"dependency_job_id":"c2dc905e-8a08-4f38-b068-1f2d04299d27","html_url":"https://github.com/pgreze/hackingWithSwift","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgreze%2FhackingWithSwift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgreze%2FhackingWithSwift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgreze%2FhackingWithSwift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgreze%2FhackingWithSwift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pgreze","download_url":"https://codeload.github.com/pgreze/hackingWithSwift/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241374682,"owners_count":19952571,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-12T05:28:10.720Z","updated_at":"2026-05-11T08:37:56.224Z","avatar_url":"https://github.com/pgreze.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"## https://www.hackingwithswift.com/read\n\nhttps://github.com/twostraws/HackingWithSwift\n\n### https://www.hackingwithswift.com/read/1/overview\n\nhttps://www.hackingwithswift.com/read/1/3/designing-our-interface\n+ UITableViewController initial view controller\n+ NavigationController\n\nhttps://www.hackingwithswift.com/read/1/5/loading-images-with-uiimage\n+ storyboard?.instantiateViewController(withIdentifier\n+ navigationController?.pushViewController\n+ imageView.image = UIImage(named: imagePath)\n\nhttps://www.hackingwithswift.com/read/1/6/final-tweaks-hidesbarsontap-and-large-titles\n+ image aspectfit\n+ viewWillAppear `navigationController?.hidesBarsOnTap = true` to hide nav bar if click image\n+ `Accessory: Disclosure Indicator` to show the \u003e arrow in all cells (aka Disclosure Indicator)\n+ custom VC title in code\n+ `navigationController?.navigationBar.prefersLargeTitles = true` for large header\n+ `navigationItem.largeTitleDisplayMode = .never` override for the detail screen only\n\n### https://www.hackingwithswift.com/read/2/overview\n\nhttps://www.hackingwithswift.com/read/2/5/from-outlets-to-actions-creating-an-ibaction\n+ UIAlertController\n\nWas not so interesting, so I wrote UI programmatically\nand added horizontal/vertical support.\n\n(leading // trailing) == (left // right)\n\n### https://www.hackingwithswift.com/read/3/overview\n\nhttps://www.hackingwithswift.com/read/3/2/uiactivityviewcontroller-explained\n\nShare button in the nav. bar:\n```swift\nnavigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareTapped))\n```\n\nshareTapped function:\n```swift\nguard let image: Data = imageView.image?.jpegData(compressionQuality: 0.8) else {\n    print(\"No image to share\")\n    return\n}\nlet vc = UIActivityViewController(activityItems: [image, \"photo.jpeg\"], applicationActivities: [])\n// For iPad, allows to show the share dialog next to the button triggering the action.\nvc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem\npresent(vc, animated: true)\n```\n\n### https://www.hackingwithswift.com/read/4/overview\n\nhttps://www.hackingwithswift.com/read/4/2/creating-a-simple-browser-with-wkwebview\n\n```swift\nlazy var webView: WKWebView = {\n    let view = WKWebView()\n    view.navigationDelegate = self\n    return view\n}()\n\noverride func loadView() {\n    view = webView\n}\n\noverride func viewDidLoad() {\n    super.viewDidLoad()\n    navigationItem.rightBarButtonItem = UIBarButtonItem(title: \"Open\", style: .plain, target: self, action: #selector(openTapped))\n    \n    webView.load(URLRequest(url: URL(string: \"https://pgreze.dev\")!))\n    webView.allowsBackForwardNavigationGestures = true\n}\n```\n\nhttps://www.hackingwithswift.com/read/4/4/monitoring-page-loads-uitoolbar-and-uiprogressview\n\nkey-value observing (KVO):\n```swift\n// Listen for webView.estimatedProgress updates\nwebView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)\n\noverride func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {\n    // Called after using addObserver\n    if keyPath == \"estimatedProgress\" {\n        progressView.isHidden = false\n        progressView.progress = Float(webView.estimatedProgress)\n    }\n}\n```\nhttps://developer.apple.com/documentation/webkit/wkwebview/1415007-estimatedprogress\n\nhttps://www.hackingwithswift.com/read/4/5/refactoring-for-the-win\n\n```swift\nfunc webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -\u003e Void) {\n    guard let host = navigationAction.request.url?.host else { return }\n    if !urls.filter({ (url) -\u003e Bool in host.hasSuffix(url) }).isEmpty {\n        decisionHandler(.allow)\n    } else {\n        decisionHandler(.cancel)\n    }\n}\n```\n\n### https://www.hackingwithswift.com/read/5/overview\n\nhttps://www.hackingwithswift.com/read/5/3/pick-a-word-any-word-uialertcontroller\n\n```swift\nguard let path = Bundle.main.url(forResource: \"start\", withExtension: \"txt\") else { return }\nguard let startWords = try? String(contentsOf: path) else { return }\nallWords = startWords.components(separatedBy: \"\\n\")\n```\n\n```swift\n@objc private func promptForAnswer() {\n    let ac = UIAlertController(title: \"Answer\", message: nil, preferredStyle: .alert)\n    ac.addTextField { (textField) in\n        textField.accessibilityLabel = \"Insert your answer\"\n    }\n    ac.addAction(UIAlertAction(title: \"Submit\", style: .default, handler: { [weak self, weak ac] action in\n        guard let answer = ac?.textFields?[0].text else { return }\n        self?.submit(answer)\n    }))\n    present(ac, animated: true)\n}\n```\n\n### https://www.hackingwithswift.com/read/6/overview\n\nhttps://www.hackingwithswift.com/read/6/2/advanced-auto-layout\n+ \"Greater Than or Equal\" for bottom margin\n+ \"Equal Heights\" for each elements\n\nhttps://www.hackingwithswift.com/read/6/3/auto-layout-in-code-addconstraints-with-visual-format-language\n```swift\nlet labels = [\n    (\"THESE\", UIColor.red),\n    (\"ARE\", UIColor.cyan),\n    (\"SOME\", UIColor.yellow),\n    (\"AWESOME\", UIColor.green),\n    (\"LABELS\", UIColor.orange),\n].enumerated().map { (index, value) -\u003e (String, UILabel) in\n    let label = UILabel()\n    label.translatesAutoresizingMaskIntoConstraints = false\n    label.backgroundColor = value.1\n    label.text = value.0\n    label.sizeToFit()\n    return (\"label\\(index+1)\", label)\n}.reduce(into: [:]) { $0[$1.0] = $1.1 }\n\nlabels.forEach { view.addSubview($0.value) }\n\nfor label in labels.keys {\n    // H: = horizontal, | = the edge of the view (=VC)\n    // == each of our labels should stretch edge-to-edge in our view\n    // Exp: H:|[label1]|\n    addConstraints(withVisualFormat: \"H:|[\\(label)]|\")\n}\n// \"-\" = means \"space\". It's 10 points by default.\n// == \"V:|[label1]-[label2]-[label3]-[label4]-[label5]\"\naddConstraints(withVisualFormat: \"V:|\\(labels.keys.map { \"[\\($0)]\" }.joined(separator: \"-\"))\")\n\nprivate func addConstraints(withVisualFormat: String) {\n    view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: withVisualFormat, options: [], metrics: nil, views: labels))\n}\n```\n\nhttps://www.hackingwithswift.com/read/6/4/auto-layout-metrics-and-priorities-constraintswithvisualformat\n\nUse metrics as constants:\n```swift\nlet metrics = [\"labelHeight\": 88]\nview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: \"V:|[label1(labelHeight)]-[label2(labelHeight)]-[label3(labelHeight)]-[label4(labelHeight)]-[label5(labelHeight)]-\u003e=10-|\", options: [], metrics: metrics, views: labels))\n```\n\nPriority (default: 1000):\n```swift\n\"V:|[label1(labelHeight@999)]-[label2(label1)]-[label3(label1)]-[label4(label1)]-[label5(label1)]-\u003e=10-|\"\n```\n\nhttps://www.hackingwithswift.com/read/6/5/auto-layout-anchors\n\n```swift\nfor label in [label1, label2, label3, label4, label5] {\n    label.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true\n    label.heightAnchor.constraint(equalToConstant: 88).isActive = true\n}\n```\n\nhttps://theswiftdev.com/mastering-ios-auto-layout-anchors-programmatically-from-swift/\n\n### https://www.hackingwithswift.com/read/8/overview\n\nhttps://www.hackingwithswift.com/read/8/2/building-a-uikit-user-interface-programmatically\n+ create UILabel programatically\n+ NSLayoutConstraint.activate([ scoreLabel.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),\n\n### https://www.hackingwithswift.com/read/9/overview\n\n```swift\n// https://www.hackingwithswift.com/read/9/3/gcd-101-async\nDispatchQueue.global(qos: .userInitiated).async { [weak self] in\n    ...\n}\n\n// https://www.hackingwithswift.com/read/9/4/back-to-the-main-thread-dispatchqueuemain\nDispatchQueue.main.async { self.tableView.reloadData() }\n\n// https://www.hackingwithswift.com/read/9/5/easy-gcd-using-performselectorinbackground\nperformSelector(inBackground: #selector(fetchJson), with: nil)\n// And for UI:\ntableView.performSelector(onMainThread: #selector(UITableView.reloadData), with: nil, waitUntilDone: false)\nperformSelector(onMainThread: #selector(showError), with: nil, waitUntilDone: false)\n```\n\n### https://www.hackingwithswift.com/read/10/overview\n\nCollectionView!!\n\n```swift\n// https://www.hackingwithswift.com/read/10/4/importing-photos-with-uiimagepickercontroller\nnavigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addNewPerson))\n\n@objc func addNewPerson() {\n    let picker = UIImagePickerController()\n    picker.allowsEditing = true\n    picker.delegate = self\n    present(picker, animated: true)\n}\n\n// https://www.hackingwithswift.com/read/10/5/custom-subclasses-of-nsobject\nclass Person : NSObject {\n}\n```\n\n### https://www.hackingwithswift.com/read/12/overview\n\n```swift\n// https://www.hackingwithswift.com/read/12/2/reading-and-writing-basics-userdefaults\n// NSCoding is objc compatible\nclass Person: NSObject, NSCoding {\n    var name: String\n    var image: String\n    \n    init(name: String, image: String) {\n        self.name = name\n        self.image = image\n    }\n    \n    func encode(with coder: NSCoder) {\n        coder.encode(name, forKey: \"name\")\n        coder.encode(image, forKey: \"image\")\n    }\n    \n    required init?(coder: NSCoder) {\n        name = coder.decodeObject(forKey: \"name\") as? String ?? \"\"\n        image = coder.decodeObject(forKey: \"image\") as? String ?? \"\"\n    }\n}\nfunc load() {\n    let defaults = UserDefaults.standard\n    if let savedPeople = defaults.object(forKey: \"people\") as? Data {\n        if let decodedPeople = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(savedPeople) as? [Person] {\n            people = decodedPeople\n        }\n    }\n}\nfunc save() {\n    if let savedData = try? NSKeyedArchiver.archivedData(withRootObject: people, requiringSecureCoding: false) {\n        let defaults = UserDefaults.standard\n        defaults.set(savedData, forKey: \"people\")\n    }\n}\n\n// Codable is easier to use but swift only\nclass Person: NSObject, Codable { //, NSCoding {\n    var name: String\n    var image: String\n    \n    init(name: String, image: String) {\n        self.name = name\n        self.image = image\n    }\n}\nfunc load() {\n    let defaults = UserDefaults.standard\n    if let savedPeople = defaults.object(forKey: \"people\") as? Data {\n        let jsonDecoder = JSONDecoder()\n        do {\n            people = try jsonDecoder.decode([Person].self, from: savedPeople)\n        } catch {\n            print(\"Failed to load people\")\n        }\n    }\n}\nfunc save() {\n    let jsonEncoder = JSONEncoder()\n    if let savedData: Data = try? jsonEncoder.encode(people) {\n        let defaults = UserDefaults.standard\n        defaults.set(savedData, forKey: \"people\")\n    }\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpgreze%2Fhackingwithswift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpgreze%2Fhackingwithswift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpgreze%2Fhackingwithswift/lists"}