772 lines
172 KiB
JSON
772 lines
172 KiB
JSON
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"items": [
|
|
{
|
|
"originId": "tag:blogger.com,1999:blog-8954608646904080796.post-6562845574025332924",
|
|
"fingerprint": "57441f5a",
|
|
"thumbnail": [
|
|
{
|
|
"url": "https://1.bp.blogspot.com/-nSjfvVEYsOE/XZ6cEycVw3I/AAAAAAAADTI/UMdV1Seh7R8c0GdV2RgwjuAoJLW47it1gCLcBGAsYHQ/s72-c/074.jpg",
|
|
"width": 72,
|
|
"height": 72
|
|
}
|
|
],
|
|
"id": "v0v+7Ya8tssIZvd3/pcnFRr3HwvY/5YK3FGc2t65c0Y=_16db6126dbf:685a:d4506071",
|
|
"updated": 1570675865985,
|
|
"author": "Edward Feser",
|
|
"alternate": [
|
|
{
|
|
"href": "http://edwardfeser.blogspot.com/2019/10/transubstantiation-and-hylemorphism.html",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1570717724095,
|
|
"title": "Transubstantiation and hylemorphism",
|
|
"published": 1570675860000,
|
|
"origin": {
|
|
"streamId": "feed/http://edwardfeser.blogspot.com/feeds/posts/default",
|
|
"htmlUrl": "http://edwardfeser.blogspot.com/",
|
|
"title": "Edward Feser"
|
|
},
|
|
"content": {
|
|
"direction": "ltr",
|
|
"content": "<br><div><a href=\"https://1.bp.blogspot.com/-nSjfvVEYsOE/XZ6cEycVw3I/AAAAAAAADTI/UMdV1Seh7R8c0GdV2RgwjuAoJLW47it1gCLcBGAsYHQ/s1600/074.jpg\"><img border=\"0\" src=\"https://1.bp.blogspot.com/-nSjfvVEYsOE/XZ6cEycVw3I/AAAAAAAADTI/UMdV1Seh7R8c0GdV2RgwjuAoJLW47it1gCLcBGAsYHQ/s200/074.jpg\" data-original-width=\"171\" width=\"151\" data-original-height=\"226\" height=\"200\"></a></div><div><span>One of the key themes of the early modern philosophers\u2019 revolt against Scholasticism was a move away from an Aristotelian hylemorphist conception of the nature of physical substance to some variation or other of the mechanical philosophy.\u00a0 The other day I was asked a very interesting question: Can transubstantiation be formulated in terms of a mechanistic conception of physical substance rather than a hylemorphic one?\u00a0 My answer was that I would not peremptorily say that it cannot be, but that the suggestion certainly raises serious philosophical and theological problems.</span></div><a name=\"more\"></a><br> <div><span>Here\u2019s why.<span>\u00a0 </span>Hylemorphism in its most straightforward version roughly agrees with common sense about which of the things of everyday experience are distinct substances, which are different parts of the same substance, and which are aggregates rather than true substances.<span>\u00a0 </span>For example, it would say that a stone, a tree, and a dog are all distinct substances from one another; that a particular dog\u2019s nose and its right front leg are different parts of the same substance rather than distinct substances; and that a pile of stones is an aggregate rather than a substance in its own right.<span>\u00a0 </span>Of course, use of the term \u201csubstance\u201d in the technical Aristotelian sense isn\u2019t part of common sense, but even untutored common sense would surely involve the supposition that a stone, a tree, and a dog are all distinct <i>things</i> or <i>objects</i>, that the nose and leg of the dog are parts of a larger thing or object rather than separate things or objects, and that a pile of stones is a bunch of things or objects rather than a single object.<span>\u00a0 </span>At least to that extent, common sense would more or less agree with what I am calling a straightforward version of hylemorphism. <span>\u00a0</span>(See chapter 3 of <i><a href=\"https://www.amazon.com/Scholastic-Metaphysics-A-Contemporary-Introduction/dp/3868385444/ref=sr_1_1?ie=UTF8&qid=1391482601&sr=8-1&keywords=scholastic+metaphysics+a+contemporary+introduction\">Scholastic Metaphysics</a></i> for exposition and defense of the hylemorphist account of substance.)</span></div><div><span><br></span></div><div><span>Now, the mechanical world picture that pushed aside the hylemorphist model tended radically to revise the common sense understanding of physical objects in one of two general ways, depending on how mechanism was spelled out.<span>\u00a0 </span>It reduced ordinary physical objects either to mere aggregates of their innumerably many component parts, or to mere modes of some larger blob of which <i>they</i>were the parts.</span></div><div><span><br></span></div><div><span>Descartes and Spinoza essentially took the latter option.<span>\u00a0 </span>Though Descartes is often described as positing a plurality of extended substances alongside the plurality of thinking substances, his considered view seemed to be that strictly speaking, there is only a single extended substance, of which the ordinary objects of our experience are merely modifications.<span>\u00a0 </span>Spinoza more famously took such a position (or rather, he took it that <i>Deus sive Natura</i>was the one substance of which the ordinary physical objects of our experience are all modes).<span>\u00a0 </span>On this view, a stone, a tree, and a dog are not really distinct substances, but merely distinct aspects of one and the same substance \u2013 in something like the way common sense regards the color, weight, and shape of a stone to be mere modes of one and the same object, the stone.</span></div><div><span><br></span></div><div><span>Atomist and corpuscularian versions of the mechanical philosophy went in the other direction.<span>\u00a0 </span>They essentially make either atoms or corpuscles the true substances, and ordinary objects mere aggregates of these purported substances.<span>\u00a0 </span>Just as a pile of rocks is not a true substance but merely a collection of substances (or as the hylemorphist would say, being a pile of rocks is a merely accidental form rather than a substantial form), so too a stone, a tree, or a dog is on this view merely a collection of particles.<span>\u00a0 </span>In effect, the particles are the true substances, and the stone, tree, or dog is like the pile \u2013 a relatively superficial arrangement of metaphysically more fundamental entities.</span></div><div><span><br></span></div><div><span>So, to come to transubstantiation, the idea, of course, is that in the Eucharist, while the accidents of bread and wine remain, the substance of bread and wine are miraculously replaced with that of Christ.<span>\u00a0 </span>Suppose, then, that we were to adopt Descartes\u2019 version of the mechanical philosophy, on which there is just one big physical substance underlying all the things ordinary perceptual experience reveals to us.<span>\u00a0 </span>That would entail that the substance that underlies the accidents of bread and wine that are about to be consecrated is the very same substance as that which underlies stones, trees, dogs, cats, human bodies, apples, oranges, the sun, the moon, water, lead, gold, and every other thing we see, hear, taste, touch, or smell.<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span>But in that case, when transubstantiation occurs, it is not just the substance underlying the accidents of bread and wine that is replaced, but the substance underlying all of these other things too.<span>\u00a0 </span>In other words, after transubstantiation occurs, it is really the body and blood of Christ that underlies what we perceive as stones, trees, dogs, cats, human bodies, the sun, the moon, water, etc.!<span>\u00a0 </span><i>Everything</i> in the physical world would be transubstantiated.<span>\u00a0 </span>We would be left with a kind of pantheism.<span>\u00a0 </span>Absolutely <i>every</i> physical thing would have to treated with the same reverence that the Eucharist is, because every physical thing would be the Eucharist!</span></div><div><span><br></span></div><div><span>Another bizarre implication of this is that transubstantiation could occur only once.<span>\u00a0 </span>For only at the first time it occurs is the one physical substance replaced by that of Christ.<span>\u00a0 </span>If a priest were ever to try to consecrate bread and wine again, he would fail, because there is no longer any physical substance there to <i>be</i> replaced.<span>\u00a0 </span>It is <i>already</i>the body and blood of Christ.</span></div><div><span><br></span></div><div><span>Suppose we went the other route, that of either atomism or corpuscularianism.<span>\u00a0 </span>Then, like stones, trees, and dogs, bread and wine would not be true substances but merely accidental collections of innumerably many true substances.<span>\u00a0 </span>They would be like a pile of rocks, only instead it would be fundamental particles (atoms or corpuscles, depending on your favored version of the mechanical philosophy) that would be piled up.<span>\u00a0 </span>But in that case, exactly <i>what </i>is the substance that is replaced when transubstantiation occurs?<span>\u00a0 </span>Neither the substance of the bread nor that of the wine can be what is replaced, because on this view they just <i>aren\u2019t</i>true substances in the first place.<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span>Should we say that it is each particle that makes up the aggregate that is transubstantiated (just as Catholic theology allows that many hosts at a time may be consecrated at Mass)?<span>\u00a0\u00a0 </span>But there are several problems with that suggestion.<span>\u00a0 </span>The first is that it is hard to know how to give a principled answer to the question what the <i>boundaries</i> are between those particles that make up the aggregate and those that are not part of it \u2013 and thus between those particles that are transubstantiated, and those that are not.<span>\u00a0 </span>The reason is that the boundaries of an aggregate are much less well defined than those of a substance.<span>\u00a0 </span>Is a stone that is two millimeters away from a pile of stones itself part of the pile or not?<span>\u00a0 </span>And is a particle that falls from the host part of <i>that</i> (purported) aggregate of particles or not?<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span>If we think of the host on the model of an Aristotelian <i>substance</i>, then we can say that a fallen particle is part of the host, like a body part that has been severed, as it were.<span>\u00a0 </span>But, again, if instead we think in terms of the model of a pile of stones or some other aggregate, the answer isn\u2019t as clear.</span></div><div><span><br></span></div><div><span>A second problem is that in Catholic theology, not any old matter can be used when consecrating the Eucharist.<span>\u00a0 </span>It has to be bread and wine, specifically.<span>\u00a0 </span>But on the interpretation under consideration, according to which bread and wine are not true substances, it is really the particles (either atoms or corpuscles) that are being consecrated.<span>\u00a0 </span>And the atoms or corpuscles that make up bread and wine are essentially the same as those that make up everything else (just as the stones that make up a pile can be essentially of the same type as those that are used instead to make up a wall).<span>\u00a0 </span>In that case, though, it would be hard to see why there is anything special about bread and wine.<span>\u00a0 </span>Why couldn\u2019t <i>any</i> old physical thing be consecrated, if every physical thing is essentially just the same kind of stuff in relatively superficial differences of configuration?</span></div><div><span><br></span></div><div><span>A third problem is that canon law says that a Catholic ought to receive communion at most only once (or in some special circumstances, perhaps twice) a day.<span>\u00a0 </span>But on the interpretation under consideration, one would in effect be consuming <i>millions</i> of consecrated hosts insofar as each of the millions of particles that make up what common sense regards as a single host was being independently transubstantiated.</span></div><div><span><br></span></div><div><span>Perhaps such problems could be solved, though I am doubtful.\u00a0 Anyway, the issue illustrates the unexpected implications that philosophical assumptions can have for theology.\u00a0 (And thus the caution that any Catholic ought to exercise before embracing philosophical novelties.\u00a0 The Scholastics knew what they were doing.)</span></div>"
|
|
},
|
|
"visual": {
|
|
"url": "https://cdn.vox-cdn.com/thumbor/qEtBNTmNKQvUro7McqHPXL-2OOM=/0x0:6720x4480/1310x873/cdn.vox-cdn.com/uploads/chorus_image/image/59664621/marshall_majorIII_aniconinthemaking_product_rgb_highres_2.0.jpg",
|
|
"width": 1310,
|
|
"height": 878,
|
|
"contentType": "image/jpeg"
|
|
},
|
|
"unread": false,
|
|
"readTime": 3562,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/5ca4d61d-e55d-4999-a8d1-c3b9d8789815",
|
|
"label": "Macintosh"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/fbdcd69b-7e27-4b6a-bfed-6584b944155d",
|
|
"label": "\ud83e\udd1e\ud83c\udffb\ud83e\udd1e\ud83c\udffb\ud83e\udd1e\ud83c\udffb"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
}
|
|
],
|
|
"actionTimestamp": 1572500351314
|
|
},
|
|
{
|
|
"keywords": [
|
|
"Xcode"
|
|
],
|
|
"originId": "https://nshipster.com/metrickit",
|
|
"recrawled": 1572363511019,
|
|
"updateCount": 2,
|
|
"fingerprint": "9be1d5cd",
|
|
"id": "CmHb1hXBWguYpGAhzgwJM9xvPVSYJFbt7KLqF3nqYQ0=_16df9da832d:14579:d4506071",
|
|
"updated": 1571641200000,
|
|
"author": "Mattt",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "<p>At WWDC this year, Apple announced a coordinated effort between Xcode 11 and iOS 13 to bring new insights to developers about how their apps are performing in the field.</p>"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "http://feedproxy.google.com/~r/NSHipster/~3/o2-j6xKjBrA/",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"canonical": [
|
|
{
|
|
"href": "https://nshipster.com/metrickit/",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1571854910253,
|
|
"title": "MetricKit",
|
|
"published": 1571641200000,
|
|
"origin": {
|
|
"streamId": "feed/http://feeds.feedburner.com/NSHipster",
|
|
"htmlUrl": "https://nshipster.com/",
|
|
"title": "NSHipster"
|
|
},
|
|
"content": {
|
|
"direction": "ltr",
|
|
"content": "<p>As an undergraduate student,\nI had a radio show called\n<em>\u201cGoodbye, Blue Monday\u201d</em>\n(I was really into Vonnegut at the time).\nIt was nothing glamorous \u2014\njust a weekly, 2-hour slot at the end of the night\nbefore the station switched into automation.</p>\n<p>If you happened to be driving through the hills of Pittsburgh, Pennsylvania\nlate at night with your radio tuned to\n<a rel=\"noopener noreferrer\" href=\"http://www.wrct.org\"><abbr title=\"Radio Carnegie Tech\">WRCT</abbr> 88.3</a>,\nyou\u2019d have heard an eclectic mix of\n<a rel=\"noopener noreferrer\" href=\"https://beta.music.apple.com/us/album/acoustica/410402556\">Contemporary Classical</a>,\n<a rel=\"noopener noreferrer\" href=\"https://beta.music.apple.com/us/album/a-funk-odyssey/203132910\">Acid Jazz</a>,\n<a rel=\"noopener noreferrer\" href=\"https://beta.music.apple.com/us/album/ma-quale-idea-single/1415038751\">Italian Disco</a>, and\n<a rel=\"noopener noreferrer\" href=\"https://beta.music.apple.com/us/album/kind-of-blue/268443092\">Bebop</a>.\nThat, and the stilting, dulcet baritone of\na college kid doing his best impersonation of\n<a rel=\"noopener noreferrer\" href=\"http://old.post-gazette.com/magazine/20010404mowod4.asp\">Tony Mowod</a>.</p>\n<p>Sitting there in the booth,\nwaiting for tracks to play out before launching into an\n<abbr title=\"Federal Communications Commission\">FCC</abbr>-mandated\n<abbr title=\"Public Service Announcement\">PSA</abbr>\nor on-the-hour\n<a rel=\"noopener noreferrer\" href=\"https://en.wikipedia.org/wiki/Station_identification\">station identification</a>,\nI\u2019d wonder:\n<em>Is anyone out there listening?</em>\n<em>And if they were, did they like it?</em>\nI could\u2019ve been broadcasting static the whole time and been none the wiser.</p>\n<p>The same thoughts come to mind whenever I submit a build to App Store Connect\u2026\nbut then I\u2019ll remember that, unlike radio,\nyou <em>can</em> actually know these things!\nAnd the latest improvements in Xcode 11 make it easier than ever\nto get an idea of how your apps are performing in the field.</p>\n<p>We\u2019ll cover everything you need to know in this week\u2019s NSHipster article.\nSo as they say on the radio:\n<em>\u201cDon\u2019t touch that dial (it\u2019s got jam on it)\u201d.</em></p>\n<hr>\n<p>MetricKit is a new framework in iOS 13\nfor collecting and processing battery and performance metrics.\nIt was announced at <a href=\"https://nshipster.com/wwdc-2019/\">WWDC this year</a>\nalong with XCTest Metrics and the Xcode Metrics Organizer\nas part of a coordinated effort to bring new insights to developers\nabout how their apps are performing in the field.</p>\n<figure>\n<picture>\n<source srcset=\"https://nshipster.com/assets/metrickit-diagram--dark-b7358fa1e9bdf87502044ad241ffcfe5bb904cb7d1bf948d38b0f35b3e93fc59.png\" media=\"(prefers-color-scheme: dark)\">\n<img alt=\"MetricKit Diagram\" src=\"https://nshipster.com/assets/metrickit-diagram--light-0dd5dd5af36c169873c46b2be3155f50aa5ccbfd98a8794bdd5e0d510eb9a42d.png\">\n</picture>\n<figcaption>Diagram from WWDC 2019 Session 417: <a rel=\"noopener noreferrer\" href=\"https://developer.apple.com/videos/play/wwdc2019/417/\">"Improving Battery Life and Performance"</a></figcaption>\n</figure>\n<p>Apple automatically collects metrics from apps installed on the App Store.\nYou can view them in Xcode 11\nby opening the Organizer (<kbd>\u2325</kbd><kbd>\u2318</kbd><kbd>\u21e7</kbd><kbd>O</kbd>)\nand selecting the new Metrics tab.</p>\n<p>MetricKit complement Xcode Organizer Metrics by providing a programmatic way to\nreceive daily information about how your app is performing in the field.\nWith this information,\nyou can collect, aggregate, and analyze on your own in greater detail\nthan you can through Xcode.</p>\n<h2>\n<a href=\"https://nshipster.com/metrickit/#understanding-app-metrics\"></a>Understanding App Metrics</h2>\n<p>Metrics can help uncover issues you might not have seen while testing locally,\nand allow you to track changes across different versions of your app.\nFor this initial release,\nApple has focused on the two metrics that matter most to users:\n<dfn>battery usage</dfn> and <dfn>performance</dfn>.</p>\n<h3>\n<a href=\"https://nshipster.com/metrickit/#battery-usage\"></a>Battery Usage</h3>\n<picture>\n<source srcset=\"https://nshipster.com/assets/metrickit-battery-usage--dark-a04760e5bcf6bb9da1153f10b37c074d3ecee9cba5887cf1065bee0a4e545d95.png\" media=\"(prefers-color-scheme: dark)\">\n<img alt=\"MetricKit Diagram\" src=\"https://nshipster.com/assets/metrickit-battery-usage--light-999245ecb5a77e77835214efce028de4fe854da718ef7b7b86730ad8812383ca.png\">\n</picture>\n<p>Battery life depends on a lot of different factors.\nPhysical aspects like the age of the device and\nthe number of charge cycles are determinative,\nbut the way your phone is used matters, too.\nThings like CPU usage,\nthe brightness of the display and the colors on the screen,\nand how often radios are used to fetch data or get your current location \u2014\nall of these can have a big impact.\nBut the main thing to keep in mind is that\nusers care a lot about battery life.</p>\n<p>Aside from how good the camera is,\nthe amount of time between charges\nis <em>the</em> deciding factor when someone buys a new phone these days.\nSo when their new, expensive phone <em>doesn\u2019t</em> make it through the day,\nthey\u2019re going to be pretty unhappy.</p>\n<p>Until recently,\nApple\u2019s taken most of the heat on battery issues.\nBut since iOS 12 and its new\n<a rel=\"noopener noreferrer\" href=\"https://support.apple.com/en-us/HT201264\">Battery Usage screen</a> in Settings,\nusers now have a way to tell when their favorite app is to blame.\nFortunately,\nwith iOS 13 you now have everything you need to make sure\nyour app doesn\u2019t run afoul of reasonable energy usage.</p>\n<h3>\n<a href=\"https://nshipster.com/metrickit/#performance\"></a>Performance</h3>\n<p>Performance is another key factor in the overall user experience.\nNormally, we might look to stats like\nprocessor clock speed or <a href=\"https://nshipster.com/uitableviewheaderfooterview/\">frame rate</a>\nas a measure of performance.\nBut instead,\nApple\u2019s focusing on less abstract and more actionable metrics:</p>\n<dl>\n<dt>Hang Rate</dt>\n<dd>How often is the main / UI thread blocked,\nsuch that the app is unresponsive to user input?</dd>\n<dt>Launch Time</dt>\n<dd>How long does an app take to become usable after the user taps its icon?</dd>\n<dt>Peak Memory & Memory at Suspension</dt>\n<dd>How much memory does the app use at its peak\nand just before entering the background?</dd>\n<dt>Disk Writes</dt>\n<dd>How often does the app write to disk,\nwhich \u2014 if you didn\u2019t already know \u2014 is a\n<a rel=\"noopener noreferrer\" href=\"https://people.eecs.berkeley.edu/~rcs/research/interactive_latency.html\">comparatively slow operation</a>\n<em>(even with the flash storage on an iPhone!)</em>\n</dd>\n</dl>\n<h2>\n<a href=\"https://nshipster.com/metrickit/#using-metrickit\"></a>Using MetricKit</h2>\n<p>From the perspective of an API consumer,\nit\u2019s hard to imagine how MetricKit could be easier to incorporate.\nAll you need is for some part of your app to serve as\na metric subscriber\n(an obvious choice is your <code>App<wbr>Delegate</code>),\nand for it to be added to the shared <code>MXMetric<wbr>Manager</code>:</p>\n<pre data-lang=\"Swift\"><code><span>import</span> <span>UIKit</span>\n <span>import</span> <span>Metric<wbr>Kit</span>\n <span>@UIApplication<wbr>Main</span>\n <span>class</span> <span>App<wbr>Delegate</span><span>:</span> <span>UIResponder</span><span>,</span> <span>UIApplication<wbr>Delegate</span> <span>{</span>\n <span>func</span> <span>application</span><span>(</span><span>_</span> <span>application</span><span>:</span> <span>UIApplication</span><span>,</span> <span>did<wbr>Finish<wbr>Launching<wbr>With<wbr>Options</span> <span>launch<wbr>Options</span><span>:</span> <span>[</span><span>UIApplication</span><span>.</span><span>Launch<wbr>Options<wbr>Key</span><span>:</span> <span>Any</span><span>]?)</span> <span>-></span> <span>Bool</span> <span>{</span>\n <span>MXMetric<wbr>Manager</span><span>.</span><span>shared</span><span>.</span><span>add</span><span>(</span><span>self</span><span>)</span>\n <span>return</span> <span>true</span>\n <span>}</span>\n <span>func</span> <span>application<wbr>Will<wbr>Terminate</span><span>(</span><span>_</span> <span>application</span><span>:</span> <span>UIApplication</span><span>)</span> <span>{</span>\n <span>MXMetric<wbr>Manager</span><span>.</span><span>shared</span><span>.</span><span>remove</span><span>(</span><span>self</span><span>)</span>\n <span>}</span>\n <span>}</span>\n <span>extension</span> <span>App<wbr>Delegate</span><span>:</span> <span>MXMetric<wbr>Manager<wbr>Subscriber</span> <span>{</span>\n <span>func</span> <span>did<wbr>Receive</span><span>(</span><span>_</span> <span>payloads</span><span>:</span> <span>[</span><span>MXMetric<wbr>Payload</span><span>])</span> <span>{</span>\n <var>...</var>\n <span>}</span>\n <span>}</span>\n </code></pre>\n<p>iOS automatically collects samples while your app is being used,\nand once per day (every 24 hours),\nit\u2019ll send an aggregated report with those metrics.</p>\n<p>To verify that your <code>MXMetric<wbr>Manager<wbr>Subscriber</code>\nis having its delegate method called as expected,\nselect Simulate MetricKit Payloads from the Debug menu\nwhile Xcode is running your app.</p>\n<aside>\n<p>The Simulate MetricKit Payloads menu item\nrequires the app to be running on an actual device\nand is disabled for Simulator builds.</p>\n</aside>\n<h3>\n<a href=\"https://nshipster.com/metrickit/#annotating-critical-code-sections-with-signposts\"></a>Annotating Critical Code Sections with Signposts</h3>\n<p>In addition to the baseline statistics collected for you,\nyou can use the\n<a rel=\"noopener noreferrer\" href=\"https://developer.apple.com/documentation/metrickit/3214364-mxsignpost\"><code>mx<wbr>Signpost</code></a> function\nto collect metrics around the most important parts of your code.\nThis <a rel=\"noopener noreferrer\" href=\"https://developer.apple.com/documentation/os/3019241-os_signpost\">signpost</a>-backed API\ncaptures CPU time, memory, and writes to disk.</p>\n<p>For example,\nif part of your app did post-processing on audio streams,\nyou might annotate those regions with metric signposts\nto determine the energy and performance impact of that work:</p>\n<pre data-lang=\"Swift\"><code><span>let</span> <span>audio<wbr>Log<wbr>Handle</span> <span>=</span> <span>MXMetric<wbr>Manager</span><span>.</span><span>make<wbr>Log<wbr>Handle</span><span>(</span><span>category</span><span>:</span> <span>"Audio"</span><span>)</span>\n <span>func</span> <span>process<wbr>Audio<wbr>Stream</span><span>()</span> <span>{</span>\n <span>mx<wbr>Signpost</span><span>(</span><span>.</span><span>begin</span><span>,</span> <span>log</span><span>:</span> <span>audio<wbr>Log<wbr>Handle</span><span>,</span> <span>name</span><span>:</span> <span>"Process<wbr>Audio<wbr>Stream"</span><span>)</span>\n <var>...</var>\n <span>mx<wbr>Signpost</span><span>(</span><span>.</span><span>end</span><span>,</span> <span>log</span><span>:</span> <span>audio<wbr>Log<wbr>Handle</span><span>,</span> <span>name</span><span>:</span> <span>"Process<wbr>Audio<wbr>Stream"</span><span>)</span>\n <span>}</span>\n </code></pre>\n<h2>\n<a href=\"https://nshipster.com/metrickit/#creating-a-self-hosted-web-service-for-collecting-app-metrics\"></a>Creating a Self-Hosted Web Service for Collecting App Metrics</h2>\n<p>Now that you have this information,\nwhat do you do with it?\nHow do we fill that <code><var>...</var></code> placeholder in our implementation of <code>did<wbr>Receive(_:)</code>?</p>\n<p>You <em>could</em> pass that along to some paid analytics or crash reporting service,\n<em>but where\u2019s the fun in that</em>?\nLet\u2019s build our own web service to collect these for further analysis:</p>\n<h3>\n<a href=\"https://nshipster.com/metrickit/#storing-and-querying-metrics-with-postgresql\"></a>Storing and Querying Metrics with PostgreSQL</h3>\n<p>The <code>MXMetric<wbr>Payload</code> objects received by metrics manager subscribers\nhave a convenient\n<a rel=\"noopener noreferrer\" href=\"https://developer.apple.com/documentation/metrickit/mxmetricpayload/3131907-jsonrepresentation\"><code>json<wbr>Representation()</code></a> method\nthat generates something like this:</p>\n<details>\n\n<pre data-lang=\"JSON\"><code><span>{</span><span>\n</span><span>"location<wbr>Activity<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"cumulative<wbr>Best<wbr>Accuracy<wbr>For<wbr>Navigation<wbr>Time"</span><span>:</span><span> </span><span>"20 sec"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Best<wbr>Accuracy<wbr>Time"</span><span>:</span><span> </span><span>"30 sec"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Hundred<wbr>Meters<wbr>Accuracy<wbr>Time"</span><span>:</span><span> </span><span>"30 sec"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Nearest<wbr>Ten<wbr>Meters<wbr>Accuracy<wbr>Time"</span><span>:</span><span> </span><span>"30 sec"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Kilometer<wbr>Accuracy<wbr>Time"</span><span>:</span><span> </span><span>"20 sec"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Three<wbr>Kilometers<wbr>Accuracy<wbr>Time"</span><span>:</span><span> </span><span>"20 sec"</span><span>\n</span><span>},</span><span>\n</span><span>"cellular<wbr>Condition<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"cell<wbr>Condition<wbr>Time"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogram<wbr>Num<wbr>Buckets"</span><span>:</span><span> </span><span>3</span><span>,</span><span>\n</span><span>"histogram<wbr>Value"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"0"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>20</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"1 bars"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"1 bars"</span><span>\n</span><span>},</span><span>\n</span><span>"1"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>30</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"2 bars"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"2 bars"</span><span>\n</span><span>},</span><span>\n</span><span>"2"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>50</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"3 bars"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"3 bars"</span><span>\n</span><span>}</span><span>\n</span><span>}</span><span>\n</span><span>}</span><span>\n</span><span>},</span><span>\n</span><span>"meta<wbr>Data"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"app<wbr>Build<wbr>Version"</span><span>:</span><span> </span><span>"0"</span><span>,</span><span>\n</span><span>"os<wbr>Version"</span><span>:</span><span> </span><span>"i<wbr>Phone OS 13.1.3 (17A878)"</span><span>,</span><span>\n</span><span>"region<wbr>Format"</span><span>:</span><span> </span><span>"US"</span><span>,</span><span>\n</span><span>"device<wbr>Type"</span><span>:</span><span> </span><span>"i<wbr>Phone9,2"</span><span>\n</span><span>},</span><span>\n</span><span>"gpu<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"cumulative<wbr>GPUTime"</span><span>:</span><span> </span><span>"20 sec"</span><span>\n</span><span>},</span><span>\n</span><span>"memory<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"peak<wbr>Memory<wbr>Usage"</span><span>:</span><span> </span><span>"200,000 k<wbr>B"</span><span>,</span><span>\n</span><span>"average<wbr>Suspended<wbr>Memory"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"average<wbr>Value"</span><span>:</span><span> </span><span>"100,000 k<wbr>B"</span><span>,</span><span>\n</span><span>"standard<wbr>Deviation"</span><span>:</span><span> </span><span>0</span><span>,</span><span>\n</span><span>"sample<wbr>Count"</span><span>:</span><span> </span><span>500</span><span>\n</span><span>}</span><span>\n</span><span>},</span><span>\n</span><span>"signpost<wbr>Metrics"</span><span>:</span><span> </span><span>[</span><span>\n</span><span>{</span><span>\n</span><span>"signpost<wbr>Interval<wbr>Data"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogrammed<wbr>Signpost<wbr>Durations"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogram<wbr>Num<wbr>Buckets"</span><span>:</span><span> </span><span>3</span><span>,</span><span>\n</span><span>"histogram<wbr>Value"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"0"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>50</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"0 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"100 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"1"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>60</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"100 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"400 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"2"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>30</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"400 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"700 ms"</span><span>\n</span><span>}</span><span>\n</span><span>}</span><span>\n</span><span>},</span><span>\n</span><span>"signpost<wbr>Cumulative<wbr>CPUTime"</span><span>:</span><span> </span><span>"30,000 ms"</span><span>,</span><span>\n</span><span>"signpost<wbr>Average<wbr>Memory"</span><span>:</span><span> </span><span>"100,000 k<wbr>B"</span><span>,</span><span>\n</span><span>"signpost<wbr>Cumulative<wbr>Logical<wbr>Writes"</span><span>:</span><span> </span><span>"600 k<wbr>B"</span><span>\n</span><span>},</span><span>\n</span><span>"signpost<wbr>Category"</span><span>:</span><span> </span><span>"Test<wbr>Signpost<wbr>Category1"</span><span>,</span><span>\n</span><span>"signpost<wbr>Name"</span><span>:</span><span> </span><span>"Test<wbr>Signpost<wbr>Name1"</span><span>,</span><span>\n</span><span>"total<wbr>Signpost<wbr>Count"</span><span>:</span><span> </span><span>30</span><span>\n</span><span>},</span><span>\n</span><span>{</span><span>\n</span><span>"signpost<wbr>Interval<wbr>Data"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogrammed<wbr>Signpost<wbr>Durations"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogram<wbr>Num<wbr>Buckets"</span><span>:</span><span> </span><span>3</span><span>,</span><span>\n</span><span>"histogram<wbr>Value"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"0"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>60</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"0 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"200 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"1"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>70</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"201 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"300 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"2"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>80</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"301 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"500 ms"</span><span>\n</span><span>}</span><span>\n</span><span>}</span><span>\n</span><span>},</span><span>\n</span><span>"signpost<wbr>Cumulative<wbr>CPUTime"</span><span>:</span><span> </span><span>"50,000 ms"</span><span>,</span><span>\n</span><span>"signpost<wbr>Average<wbr>Memory"</span><span>:</span><span> </span><span>"60,000 k<wbr>B"</span><span>,</span><span>\n</span><span>"signpost<wbr>Cumulative<wbr>Logical<wbr>Writes"</span><span>:</span><span> </span><span>"700 k<wbr>B"</span><span>\n</span><span>},</span><span>\n</span><span>"signpost<wbr>Category"</span><span>:</span><span> </span><span>"Test<wbr>Signpost<wbr>Category2"</span><span>,</span><span>\n</span><span>"signpost<wbr>Name"</span><span>:</span><span> </span><span>"Test<wbr>Signpost<wbr>Name2"</span><span>,</span><span>\n</span><span>"total<wbr>Signpost<wbr>Count"</span><span>:</span><span> </span><span>40</span><span>\n</span><span>}</span><span>\n</span><span>],</span><span>\n</span><span>"display<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"average<wbr>Pixel<wbr>Luminance"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"average<wbr>Value"</span><span>:</span><span> </span><span>"50 apl"</span><span>,</span><span>\n</span><span>"standard<wbr>Deviation"</span><span>:</span><span> </span><span>0</span><span>,</span><span>\n</span><span>"sample<wbr>Count"</span><span>:</span><span> </span><span>500</span><span>\n</span><span>}</span><span>\n</span><span>},</span><span>\n</span><span>"cpu<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"cumulative<wbr>CPUTime"</span><span>:</span><span> </span><span>"100 sec"</span><span>\n</span><span>},</span><span>\n</span><span>"network<wbr>Transfer<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"cumulative<wbr>Cellular<wbr>Download"</span><span>:</span><span> </span><span>"80,000 k<wbr>B"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Wifi<wbr>Download"</span><span>:</span><span> </span><span>"60,000 k<wbr>B"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Cellular<wbr>Upload"</span><span>:</span><span> </span><span>"70,000 k<wbr>B"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Wifi<wbr>Upload"</span><span>:</span><span> </span><span>"50,000 k<wbr>B"</span><span>\n</span><span>},</span><span>\n</span><span>"disk<wbr>IOMetrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"cumulative<wbr>Logical<wbr>Writes"</span><span>:</span><span> </span><span>"1,300 k<wbr>B"</span><span>\n</span><span>},</span><span>\n</span><span>"application<wbr>Launch<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogrammed<wbr>Time<wbr>To<wbr>First<wbr>Draw<wbr>Key"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogram<wbr>Num<wbr>Buckets"</span><span>:</span><span> </span><span>3</span><span>,</span><span>\n</span><span>"histogram<wbr>Value"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"0"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>50</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"1,000 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"1,010 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"1"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>60</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"2,000 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"2,010 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"2"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>30</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"3,000 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"3,010 ms"</span><span>\n</span><span>}</span><span>\n</span><span>}</span><span>\n</span><span>},</span><span>\n</span><span>"histogrammed<wbr>Resume<wbr>Time"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogram<wbr>Num<wbr>Buckets"</span><span>:</span><span> </span><span>3</span><span>,</span><span>\n</span><span>"histogram<wbr>Value"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"0"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>60</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"200 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"210 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"1"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>70</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"300 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"310 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"2"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>80</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"500 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"510 ms"</span><span>\n</span><span>}</span><span>\n</span><span>}</span><span>\n</span><span>}</span><span>\n</span><span>},</span><span>\n</span><span>"application<wbr>Time<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"cumulative<wbr>Foreground<wbr>Time"</span><span>:</span><span> </span><span>"700 sec"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Background<wbr>Time"</span><span>:</span><span> </span><span>"40 sec"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Background<wbr>Audio<wbr>Time"</span><span>:</span><span> </span><span>"30 sec"</span><span>,</span><span>\n</span><span>"cumulative<wbr>Background<wbr>Location<wbr>Time"</span><span>:</span><span> </span><span>"30 sec"</span><span>\n</span><span>},</span><span>\n</span><span>"time<wbr>Stamp<wbr>End"</span><span>:</span><span> </span><span>"2019-10-22 06:59:00 +0000"</span><span>,</span><span>\n</span><span>"application<wbr>Responsiveness<wbr>Metrics"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogrammed<wbr>App<wbr>Hang<wbr>Time"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"histogram<wbr>Num<wbr>Buckets"</span><span>:</span><span> </span><span>3</span><span>,</span><span>\n</span><span>"histogram<wbr>Value"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"0"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>50</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"0 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"100 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"1"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>60</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"100 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"400 ms"</span><span>\n</span><span>},</span><span>\n</span><span>"2"</span><span>:</span><span> </span><span>{</span><span>\n</span><span>"bucket<wbr>Count"</span><span>:</span><span> </span><span>30</span><span>,</span><span>\n</span><span>"bucket<wbr>Start"</span><span>:</span><span> </span><span>"400 ms"</span><span>,</span><span>\n</span><span>"bucket<wbr>End"</span><span>:</span><span> </span><span>"700 ms"</span><span>\n</span><span>}</span><span>\n</span><span>}</span><span>\n</span><span>}</span><span>\n</span><span>},</span><span>\n</span><span>"app<wbr>Version"</span><span>:</span><span> </span><span>"1.0.0"</span><span>,</span><span>\n</span><span>"time<wbr>Stamp<wbr>Begin"</span><span>:</span><span> </span><span>"2019-10-21 07:00:00 +0000"</span><span>\n</span><span>}</span><span>\n</span></code></pre>\n</details>\n<p>As you can see,\nthere\u2019s a lot baked into this representation.\nDefining a schema for all of this information would be a lot of work,\nand there\u2019s no guarantee that this won\u2019t change in the future.\nSo instead,\nlet\u2019s embrace the NoSQL paradigm\n<em>(albeit responsibly, using <a rel=\"noopener noreferrer\" href=\"https://postgresapp.com\">Postgres</a>)</em>\nby storing payloads in a <a rel=\"noopener noreferrer\" href=\"https://www.postgresql.org/docs/current/datatype-json.html\"><code>JSONB</code> column</a>:</p>\n<pre data-lang=\"sql\"><code><span>CREATE</span> <span>TABLE</span> <span>IF</span> <span>NOT</span> <span>EXISTS</span> <span>metrics</span> <span>(</span>\n <span>id</span> <span>BIGINT</span> <span>GENERATED</span> <span>BY</span> <span>DEFAULT</span> <span>AS</span> <span>IDENTITY</span> <span>PRIMARY</span> <span>KEY</span><span>,</span>\n <span>payload</span> <span>JSONB</span> <span>NOT</span> <span>NULL</span>\n <span>);</span>\n </code></pre>\n<p><em>So easy!</em></p>\n<p>We can extract individual fields from payloads\nusing <a rel=\"noopener noreferrer\" href=\"https://www.postgresql.org/docs/current/functions-json.html\">JSON operators</a>\nlike so:</p>\n<pre data-lang=\"sql\"><code><span>SELECT</span> <span>(</span><span>payload</span> <span>-></span> <span>'application<wbr>Time<wbr>Metrics'</span>\n <span>->></span> <span>'cumulative<wbr>Foreground<wbr>Time'</span><span>)::</span><span>INTERVAL</span>\n <span>FROM</span> <span>metrics</span><span>;</span>\n <span>-- interval</span>\n <span>-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550</span>\n <span>-- @ 11 mins 40 secs</span>\n <span>-- (1 row)</span>\n </code></pre>\n<aside>\n<p>The JSON representation of metrics stores measurements for time and memory\nas strings with units (such as <code>"100 ms"</code> and <code>500 k<wbr>B</code>).\nIn Postgres, you can cast time measurements directly to the\n<a rel=\"noopener noreferrer\" href=\"https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-INTERVAL-INPUT\"><code>INTERVAL</code> type</a>,\nhowever you\u2019ll need to create a function to convert to byte counts:</p>\n<pre data-lang=\"sql\"><code><span>CREATE</span> <span>OR</span> <span>REPLACE</span> <span>FUNCTION</span> <span>parse_byte_count</span> <span>(</span><span>TEXT</span><span>)</span>\n <span>RETURNS</span> <span>BIGINT</span>\n <span>AS</span> <span>$$</span>\n <span>SELECT</span>\n <span>replace</span><span>(</span><span>split_part</span><span>(</span><span>$</span><span>1</span><span>,</span> <span>' '</span><span>,</span> <span>1</span><span>),</span><span>','</span><span>,</span><span>''</span><span>)::</span><span>BIGINT</span> <span>*</span>\n <span>CASE</span> <span>split_part</span><span>(</span><span>$</span><span>1</span><span>,</span> <span>' '</span><span>,</span> <span>2</span><span>)</span>\n <span>WHEN</span> <span>'k<wbr>B'</span> <span>THEN</span> <span>1000</span>\n <span>WHEN</span> <span>'MB'</span> <span>THEN</span> <span>1000</span> <span>*</span> <span>1000</span>\n <span>WHEN</span> <span>'GB'</span> <span>THEN</span> <span>1000</span> <span>*</span> <span>1000</span> <span>*</span> <span>1000</span>\n <span>END</span>\n <span>$$</span> <span>LANGUAGE</span> <span>'sql'</span> <span>STRICT</span> <span>IMMUTABLE</span><span>;</span>\n </code></pre>\n</aside>\n<h4>\n<a href=\"https://nshipster.com/metrickit/#advanced-creating-views\"></a>Advanced: Creating Views</h4>\n<p>JSON operators in PostgreSQL can be cumbersome to work with \u2014\nespecially for more complex queries.\nOne way to help with that is to create a view\n<em>(<a rel=\"noopener noreferrer\" href=\"https://www.postgresql.org/docs/current/rules-materializedviews.html\">materialized</a> or otherwise)</em>\nto project the most important information to you\nin the most convenient representation:</p>\n<pre data-lang=\"sql\"><code><span>CREATE</span> <span>VIEW</span> <span>key_performance_indicators</span> <span>AS</span>\n <span>SELECT</span>\n <span>id</span><span>,</span>\n <span>(</span><span>payload</span> <span>-></span> <span>'app<wbr>Version'</span><span>)</span> <span>AS</span> <span>app_version</span><span>,</span>\n <span>(</span><span>payload</span> <span>-></span> <span>'meta<wbr>Data'</span> <span>->></span> <span>'device<wbr>Type'</span><span>)</span> <span>AS</span> <span>device_type</span><span>,</span>\n <span>(</span><span>payload</span> <span>-></span> <span>'meta<wbr>Data'</span> <span>->></span> <span>'region<wbr>Format'</span><span>)</span> <span>AS</span> <span>region</span><span>,</span>\n <span>(</span><span>payload</span> <span>-></span> <span>'application<wbr>Time<wbr>Metrics'</span>\n <span>->></span> <span>'cumulative<wbr>Foreground<wbr>Time'</span>\n <span>)::</span><span>INTERVAL</span> <span>AS</span> <span>cumulative_foreground_time</span><span>,</span>\n <span>parse_byte_count</span><span>(</span>\n <span>payload</span> <span>-></span> <span>'memory<wbr>Metrics'</span>\n <span>->></span> <span>'peak<wbr>Memory<wbr>Usage'</span>\n <span>)</span> <span>AS</span> <span>peak_memory_usage_bytes</span>\n <span>FROM</span> <span>metrics</span><span>;</span>\n </code></pre>\n<p>With views,\nyou can perform\n<a rel=\"noopener noreferrer\" href=\"https://www.postgresql.org/docs/current/functions-aggregate.html\">aggregate queries</a>\nover all of your metrics JSON payloads\nwith the convenience of a schema-backed relational database:</p>\n<pre data-lang=\"sql\"><code><span>SELECT</span> <span>avg</span><span>(</span><span>cumulative_foreground_time</span><span>)</span>\n <span>FROM</span> <span>key_performance_indicators</span><span>;</span>\n <span>-- avg</span>\n <span>-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550</span>\n <span>-- @ 9 mins 41 secs</span>\n <span>SELECT</span> <span>app_version</span><span>,</span> <span>percentile_disc</span><span>(</span><span>0</span><span>.</span><span>5</span><span>)</span>\n <span>WITHIN</span> <span>GROUP</span> <span>(</span><span>ORDER</span> <span>BY</span> <span>peak_memory_usage_bytes</span><span>)</span>\n <span>AS</span> <span>median</span>\n <span>FROM</span> <span>key_performance_indicators</span>\n <span>GROUP</span> <span>BY</span> <span>app_version</span><span>;</span>\n <span>-- app_version \u2502 median</span>\n <span>-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550</span>\n <span>-- "1.0.1" \u2502 192500000</span>\n <span>-- "1.0.0" \u2502 204800000</span>\n </code></pre>\n<aside>\n<p>PostgreSQL doesn\u2019t handle camelcase well for table or column names,\nso keep that in mind when using functions like\n<a rel=\"noopener noreferrer\" href=\"https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSON-PROCESSING-TABLE\"><code>jsonb_to_record</code></a>.</p>\n</aside>\n<h3>\n<a href=\"https://nshipster.com/metrickit/#creating-a-web-service\"></a>Creating a Web Service</h3>\n<p>In this example,\nmost of the heavy lifting is delegated to Postgres,\nmaking the server-side implementation rather boring.\nFor completeness,\nhere are some reference implementations in\nRuby (Sinatra) and JavaScript (Express):</p>\n<div>\n<div>\n\n\n</div>\n<pre data-lang=\"Ruby\" tabindex=\"0\"><code><span>require</span> <span>'sinatra/base'</span>\n <span>require</span> <span>'pg'</span>\n <span>require</span> <span>'sequel'</span>\n <span>class</span> <span>App</span> <span><</span> <span>Sinatra</span><span>::</span><span>Base</span>\n <span>configure</span> <span>do</span>\n <span>DB</span> <span>=</span> <span>Sequel</span><span>.</span><span>connect</span><span>(</span><span>ENV</span><span>[</span><span>'DATABASE_URL'</span><span>])</span>\n <span>end</span>\n <span>post</span> <span>'/collect'</span> <span>do</span>\n <span>DB</span><span>[</span><span>:metrics</span><span>].</span><span>insert</span><span>(</span><span>payload: </span><span>request</span><span>.</span><span>body</span><span>.</span><span>read</span><span>)</span>\n <span>status</span> <span>204</span>\n <span>end</span>\n <span>end</span>\n </code></pre>\n<pre data-lang=\"JavaScript\" hidden=\"hidden\" tabindex=\"0\"><code><span>import</span> <span>express</span> <span>from</span> <span>'express'</span><span>;</span>\n <span>import</span> <span>{</span> <span>Pool</span> <span>}</span> <span>from</span> <span>'pg'</span><span>;</span>\n <span>const</span> <span>db</span> <span>=</span> <span>new</span> <span>Pool</span><span>(</span>\n <span>connection<wbr>String</span><span>:</span> <span>process</span><span>.</span><span>env</span><span>.</span><span>DATABASE_URL</span><span>,</span>\n <span>ssl</span><span>:</span> <span>process</span><span>.</span><span>env</span><span>.</span><span>NODE_ENV</span> <span>===</span> <span>'production'</span>\n <span>);</span>\n <span>const</span> <span>app</span> <span>=</span> <span>express</span><span>();</span>\n <span>app</span><span>.</span><span>post</span><span>(</span><span>'/collect'</span><span>,</span> <span>(</span><span>request</span><span>,</span> <span>response</span><span>)</span> <span>=></span> <span>{</span>\n <span>db</span><span>.</span><span>query</span><span>(</span><span>'INSERT INTO metrics (payload) VALUES ($1)'</span><span>,</span> <span>[</span><span>request</span><span>.</span><span>body</span><span>],</span> <span>(</span><span>error</span><span>,</span> <span>results</span><span>)</span> <span>=></span> <span>{</span>\n <span>if</span> <span>(</span><span>error</span><span>)</span> <span>{</span>\n <span>throw</span> <span>error</span><span>;</span>\n <span>}</span>\n <span>response</span><span>.</span><span>status</span><span>(</span><span>204</span><span>);</span>\n <span>})</span>\n <span>});</span>\n <span>app</span><span>.</span><span>listen</span><span>(</span><span>process</span><span>.</span><span>env</span><span>.</span><span>PORT</span> <span>||</span> <span>5000</span><span>)</span>\n </code></pre>\n</div>\n<h3>\n<a href=\"https://nshipster.com/metrickit/#sending-metrics-as-json\"></a>Sending Metrics as JSON</h3>\n<p>Now that we have everything set up,\nthe final step is to implement\nthe required <code>MXMetric<wbr>Manager<wbr>Subscriber</code> delegate method <code>did<wbr>Receive(_:)</code>\nto pass that information along to our web service:</p>\n<pre data-lang=\"Swift\"><code><span>extension</span> <span>App<wbr>Delegate</span><span>:</span> <span>MXMetric<wbr>Manager<wbr>Subscriber</span> <span>{</span>\n <span>func</span> <span>did<wbr>Receive</span><span>(</span><span>_</span> <span>payloads</span><span>:</span> <span>[</span><span>MXMetric<wbr>Payload</span><span>])</span> <span>{</span>\n <span>for</span> <span>payload</span> <span>in</span> <span>payloads</span> <span>{</span>\n <span>let</span> <span>url</span> <span>=</span> <span>URL</span><span>(</span><span>string</span><span>:</span> <span>"https://example.com/collect"</span><span>)</span><span>!</span>\n <span>var</span> <span>request</span> <span>=</span> <span>URLRequest</span><span>(</span><span>url</span><span>:</span> <span>url</span><span>)</span>\n <span>request</span><span>.</span><span>http<wbr>Method</span> <span>=</span> <span>"POST"</span>\n <span>request</span><span>.</span><span>http<wbr>Body</span> <span>=</span> <span>payload</span><span>.</span><span>json<wbr>Representation</span><span>()</span>\n <span>let</span> <span>task</span> <span>=</span> <span>URLSession</span><span>.</span><span>shared</span><span>.</span><span>data<wbr>Task</span><span>(</span><span>with</span><span>:</span> <span>request</span><span>)</span>\n <span>task</span><span>.</span><span>priority</span> <span>=</span> <span>URLSession<wbr>Task</span><span>.</span><span>low<wbr>Priority</span>\n <span>task</span><span>.</span><span>resume</span><span>()</span>\n <span>}</span>\n <span>}</span>\n <span>}</span>\n </code></pre>\n<hr>\n<p>When you create something and put it out into the world,\nyou lose your direct connection to it.\nThat\u2019s as true for apps as it is for college radio shows.\nShort of user research studies or\n<a rel=\"noopener noreferrer\" href=\"https://techcrunch.com/2019/02/06/iphone-session-replay-screenshots/\">invasive ad-tech</a>,\nthe truth is that\n<a rel=\"noopener noreferrer\" href=\"https://xkcd.com/1172/\">we rarely have any clue about how people are using our software</a>.</p>\n\n<p>Metrics offer a convenient way to at least make sure that\nthings aren\u2019t too slow or too draining.\nAnd though they provide but a glimpse in the aggregate\nof how our apps are being enjoyed,\nit\u2019s just enough to help us honor both our creation and our audience\nwith a great user experience.</p>\n\n<img width=\"1\" alt=\"\" src=\"http://feeds.feedburner.com/~r/NSHipster/~4/o2-j6xKjBrA\" height=\"1\">"
|
|
},
|
|
"visual": {
|
|
"url": "https://cdn.vox-cdn.com/thumbor/06e5FJWgUfUSmDaPJIEZoGF1XOs=/0x68:2040x1136/fit-in/1200x630/cdn.vox-cdn.com/uploads/chorus_asset/file/10378819/DSCF3031.jpg",
|
|
"width": 1200,
|
|
"height": 628,
|
|
"contentType": "image/jpeg"
|
|
},
|
|
"unread": false,
|
|
"readTime": 4744,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/e31b3fcb-27f6-4f3e-b96c-53902586e366",
|
|
"label": "Weblogs"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
}
|
|
],
|
|
"actionTimestamp": 1572500250190
|
|
},
|
|
{
|
|
"originId": "https://inessential.com/2019/10/22/netnewswire_5_0_3_for_mac_released",
|
|
"fingerprint": "2c4d6d88",
|
|
"id": "+jHfsXnBCVfCstSIW1WDumAyigT4rnsUPnI5WFxgnAU=_16df54dfcca:13322:d4506071",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "<p><a href=\"https://ranchero.com/netnewswire/\"><img width=\"256\" alt=\"NetNewsWire for Mac icon: globe with a satellite in the foreground.\" src=\"https://ranchero.com/images/nnw_icon_256.png\" height=\"256\"></a></p>\n<p>The main things in this release are 1) enhanced performance and 2) importing subscriptions from NetNewsWire 3 (since it won\u2018t run on Catalina).</p>\n<p>There are also a bunch of bug fixes \u2014 including a fix for the space bar behavior on Catalina \u2014 and there\u2019s a new feature: you can type the <code>s</code> key to star and unstar an article.</p>\n<p>For more details, <a href=\"https://nnw.ranchero.com/2019/10/22/netnewswire-for-mac.html\">read the change notes</a> on the NetNewsWire blog.</p>"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://inessential.com/2019/10/22/netnewswire_5_0_3_for_mac_released",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1571778591946,
|
|
"title": "NetNewsWire 5.0.3 for Mac Released",
|
|
"published": 1571775505000,
|
|
"origin": {
|
|
"streamId": "feed/http://ranchero.com/xml/rss.xml",
|
|
"htmlUrl": "https://inessential.com/",
|
|
"title": "inessential.com"
|
|
},
|
|
"visual": {
|
|
"url": "http://www.blogcdn.com/www.engadget.com/media/2013/10/nvidia-shield-console-mode.jpg",
|
|
"width": 620,
|
|
"height": 340,
|
|
"contentType": "image/jpg"
|
|
},
|
|
"unread": false,
|
|
"readTime": 5621,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/66132046-6f14-488d-b590-8e93422723c8",
|
|
"label": "THree"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
}
|
|
],
|
|
"actionTimestamp": 1572500226675
|
|
},
|
|
{
|
|
"id": "AxO6mug+YPRclcA3EJcsykvvS1qcjXH62IXONGWCBII=_16db2add61b:afd:a4acdac",
|
|
"originId": "58495.pz39s0 at https://www.imore.com",
|
|
"fingerprint": "8fe463a6",
|
|
"content": {
|
|
"content": "<div><div><div><p>An Apple Support rep apparently said, "I do not know how this could of happened."</p>\n<p><a href=\"https://www.imore.com/apple-card-user-says-he-was-victim-fraud\" title=\"Apple Card user says he was the victim of fraud\"><img src=\"https://www.imore.com/sites/imore.com/files/styles/large_wm_blw/public/field/image/2019/08/apple-card-hero-05.jpeg?itok=IWclhnvc\"></a></p>\n<h2>What you need to know</h2>\n<ul><li>An Apple Card user claims he was the victim of fraud.</li>\n<li>When he contacted Apple Support, they said, "I do not know how this could of happened."</li>\n<li>Apple Card touts an extra level of security with no numbers and no CVV.</li>\n</ul><p>When Apple Card debuted, one of its biggest draws was Apple's focus on security. On Apple's website, it says, "It's hard to steal a credit card number when you can't see it." But that's apparently what happened to one Apple Card user who reached out to <a href=\"https://9to5mac.com/2019/10/09/apple-card-security-cloning/\">9to5Mac</a>, claiming they were the victim of fraud.</p>\n<p>The Apple Card user said they reached out to Apple Support and received this response:</p>\n<blockquote>\n<p>I do not know how this could of happened. It's very rare for your card to be in two places at one time. Since our physical cards have no number on it, it's very hard for someone to copy it.</p>\n</blockquote>\n<p>The Apple Card user confirmed the fraudulent charge after receiving an alert on his iPhone. The tricky thing is the purchase was apparently labeled as being nearby, but clicking on the map revealed it was hours away, 9to5Mac explained.</p>\n<p>On Apple's website, the company highlights the fact that the Apple Card doesn't have any numbers on it. "Not even a CVV. So that's one less thing to worry about when you hand over your card at a restaurant or store." But that doesn't guarantee it can't be stolen.</p>\n<p>9to5Mac speculates that the Apple Card user may have been the victim of skimming, which can potentially affect all credit cards and debit cards. It's a reminder to be extra vigilant when swiping your card at a gas station or ATM. Better yet, use Apple Pay when possible.</p>\n<p></p><p></p>\n<div>\n<h3><a href=\"https://www.imore.com/apple-goldman-sachs-credit-card\">Apple Card</a></h3>\n<p><a href=\"https://www.imore.com/apple-goldman-sachs-credit-card\"></a><a href=\"https://www.imore.com/apple-card-user-says-he-was-victim-fraud\" title=\"Apple Card user says he was the victim of fraud\"><img src=\"https://www.imore.com/sites/imore.com/files/styles/large/public/field/image/2019/03/apple-card-iphone-xs-payment.jpg\"></a></p>\n<ul><li><a href=\"https://www.imore.com/apple-goldman-sachs-credit-card\">Apple Card: Everything you need to know</a></li>\n<li><a href=\"https://www.imore.com/amex-business-gold-card-apple-store-rewards\">Best Apple Store rewards card</a></li>\n<li><a href=\"https://www.imore.com/apple-card-missing-these-huge-signup-bonuses\">Best credit cards with sign up bonuses</a></li>\n<li><a href=\"https://www.imore.com/not-approved-apple-card-try-applying-these-cards-instead\">What to do if you're not approved for Apple Card</a></li>\n<li><a href=\"https://www.imore.com/is-apple-card-worth-getting\">Is Apple Card worth getting?</a></li>\n</ul></div>\n<p></p></div></div></div><img width=\"1\" alt=\"\" src=\"http://feeds.feedburner.com/~r/TheIphoneBlog/~4/DzBrQNf9PCU\" height=\"1\">",
|
|
"direction": "ltr"
|
|
},
|
|
"title": "Apple Card user says he was the victim of fraud",
|
|
"author": "Brandon Russell",
|
|
"summary": {
|
|
"content": "An Apple Support rep apparently said, "I do not know how this could of happened."\nWhat you need to know\nAn Apple Card user claims he was the victim of fraud.\nWhen he contacted Apple Support, they said, "I do not know how this could of happened."\nApple Card touts an extra level of security with no numbers and no CVV.\nWhen Apple Card debuted, one of its biggest draws was Apple's focus on security. On Apple's website, it says, "It's hard to steal a credit card number when you can't see it." But that's apparently what happened to one Apple Card user who reached out to 9to5Mac, claiming they were the victim of fraud.\nThe Apple Card user said they reached out to Apple Support and received this response:\nI do not know how this could of happened. It's very rare for your card to be in two places at one time. Since our physical cards have no number on it, it's very hard for someone to copy it.\nThe Apple Card user confirmed the fraudulent charge after receiving an alert on his iPhone. ...",
|
|
"direction": "ltr"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "http://feeds.imore.com/~r/TheIphoneBlog/~3/DzBrQNf9PCU/apple-card-user-says-he-was-victim-fraud",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"canonical": [
|
|
{
|
|
"href": "https://www.imore.com/apple-card-user-says-he-was-victim-fraud",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1570660800027,
|
|
"published": 1570660313000,
|
|
"origin": {
|
|
"streamId": "feed/http://www.imore.com/rss.xml",
|
|
"title": "iMore - The #1 iPhone, iPad, and iPod touch blog",
|
|
"htmlUrl": "https://www.imore.com/"
|
|
},
|
|
"unread": false,
|
|
"readTime": 2216,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/66132046-6f14-488d-b590-8e93422723c8",
|
|
"label": "THree"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
}
|
|
],
|
|
"actionTimestamp": 1572500208603
|
|
},
|
|
{
|
|
"keywords": [
|
|
"Development",
|
|
"How To",
|
|
"Xcode"
|
|
],
|
|
"originId": "https://ericasadun.com/?p=6502",
|
|
"fingerprint": "878bb7e8",
|
|
"id": "eos9yhbovnwyH+gNY6NsrxoZIGI+1zv2KFTRDDBJycA=_16e0e491282:185ad:d4506071",
|
|
"author": "erica",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "Most Xcode users quickly become familiar with the basics of the Find Navigator panel. With it, you can find text, regular expressions, and perform search-and-replace, whether matching or ignoring case. But that\u2019s just scratching the surface of the Find Navigator. I thought I\u2019d drop a few words today about search scopes. Controlled from the bottom [\u2026]"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://ericasadun.com/2019/10/27/fun-with-xcode-search-domains-excluding-match-text/",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1572197700226,
|
|
"title": "Fun with Xcode Search Domains: Excluding match text",
|
|
"published": 1572195876000,
|
|
"origin": {
|
|
"streamId": "feed/http://ericasadun.com/feed/",
|
|
"htmlUrl": "https://ericasadun.com",
|
|
"title": "Erica Sadun"
|
|
},
|
|
"content": {
|
|
"direction": "ltr",
|
|
"content": "<p>Most Xcode users quickly become familiar with the basics of the Find Navigator panel.</p>\n<p><img data-orig-file=\"https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.32.34-AM.png?fit=273%2C104&ssl=1\" data-orig-size=\"273,104\" data-medium-file=\"https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.32.34-AM.png?fit=273%2C104&ssl=1\" data-attachment-id=\"6503\" data-image-meta=\"{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}\" data-image-description=\"\" src=\"https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.32.34-AM.png?resize=273%2C104&ssl=1\" data-permalink=\"https://ericasadun.com/2019/10/27/fun-with-xcode-search-domains-excluding-match-text/screen-shot-2019-10-27-at-10-32-34-am/\" data-large-file=\"https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.32.34-AM.png?fit=273%2C104&ssl=1\" alt=\"\" data-image-title=\"Screen Shot 2019-10-27 at 10.32.34 AM\" width=\"273\" data-comments-opened=\"1\" class=\"wp-image-6503\" data-recalc-dims=\"1\" height=\"104\"></p>\n<p>With it, you can find text, regular expressions, and perform search-and-replace, whether matching or ignoring case. But that\u2019s just scratching the surface of the Find Navigator.</p>\n<p>I thought I\u2019d drop a few words today about search scopes. Controlled from the bottom left, \u00a0under the search field, you can create narrowed searches. This enables you to, for example, search only in Swift files or exclude files containing the word Test.</p>\n<p>To get started, click the icon (two lines with three squares on a line between them) and then New Scope (the plus icon). Here, you can name the scope, limit the search extent, and add criteria for exactly which files should be included or not.</p>\n<p><img data-orig-file=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.37.57-AM.png?fit=863%2C223&ssl=1\" data-orig-size=\"863,223\" data-medium-file=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.37.57-AM.png?fit=300%2C78&ssl=1\" data-attachment-id=\"6504\" data-image-meta=\"{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}\" data-image-description=\"\" src=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.37.57-AM.png?resize=863%2C223&ssl=1\" data-permalink=\"https://ericasadun.com/2019/10/27/fun-with-xcode-search-domains-excluding-match-text/screen-shot-2019-10-27-at-10-37-57-am/\" data-large-file=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.37.57-AM.png?fit=863%2C223&ssl=1\" alt=\"\" data-image-title=\"Screen Shot 2019-10-27 at 10.37.57 AM\" srcset=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.37.57-AM.png?w=863&ssl=1 863w, https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.37.57-AM.png?resize=300%2C78&ssl=1 300w, https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.37.57-AM.png?resize=768%2C198&ssl=1 768w, https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.37.57-AM.png?resize=535%2C138&ssl=1 535w\" sizes=\"(max-width: 863px) 100vw, 863px\" width=\"863\" data-comments-opened=\"1\" class=\"wp-image-6504\" data-recalc-dims=\"1\" height=\"223\"></p>\n<p>The logic is straightforward. You choose where to look (the project, a folder, or through the entire SDK), and whether to include all conditions or some conditions:</p>\n<p><img data-orig-file=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.49-AM.png?fit=310%2C105&ssl=1\" data-orig-size=\"310,105\" data-medium-file=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.49-AM.png?fit=300%2C102&ssl=1\" data-attachment-id=\"6505\" data-image-meta=\"{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}\" data-image-description=\"\" src=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.49-AM.png?resize=310%2C105&ssl=1\" data-permalink=\"https://ericasadun.com/2019/10/27/fun-with-xcode-search-domains-excluding-match-text/screen-shot-2019-10-27-at-10-39-49-am/\" data-large-file=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.49-AM.png?fit=310%2C105&ssl=1\" alt=\"\" data-image-title=\"Screen Shot 2019-10-27 at 10.39.49 AM\" srcset=\"https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.49-AM.png?w=310&ssl=1 310w, https://i2.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.49-AM.png?resize=300%2C102&ssl=1 300w\" sizes=\"(max-width: 310px) 100vw, 310px\" width=\"310\" data-comments-opened=\"1\" class=\"wp-image-6505\" data-recalc-dims=\"1\" height=\"105\"></p>\n<p>Each condition is based on the file name, path, extension, UTI (the kind of file, like image which is useful for finding vector assets), Workspace location (namely groups), or source control status (handy for finding newly applied changes.)</p>\n<p>Most of my conditions are file-name-based. And for those, you get the following matching conditions. The \u201cends with\u201d is an obvious win for extensions (although you can also use UTIs for that), and \u201cstarts with\u201d can help for projects organized in hierarchical ways.</p>\n<p><img data-orig-file=\"https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.44-AM.png?fit=484%2C113&ssl=1\" data-orig-size=\"484,113\" data-medium-file=\"https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.44-AM.png?fit=300%2C70&ssl=1\" data-attachment-id=\"6506\" data-image-meta=\"{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}\" data-image-description=\"\" src=\"https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.44-AM.png?resize=484%2C113&ssl=1\" data-permalink=\"https://ericasadun.com/2019/10/27/fun-with-xcode-search-domains-excluding-match-text/screen-shot-2019-10-27-at-10-39-44-am/\" data-large-file=\"https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.44-AM.png?fit=484%2C113&ssl=1\" alt=\"\" data-image-title=\"Screen Shot 2019-10-27 at 10.39.44 AM\" srcset=\"https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.44-AM.png?w=484&ssl=1 484w, https://i0.wp.com/ericasadun.com/wp-content/uploads/2019/10/Screen-Shot-2019-10-27-at-10.39.44-AM.png?resize=300%2C70&ssl=1 300w\" sizes=\"(max-width: 484px) 100vw, 484px\" width=\"484\" data-comments-opened=\"1\" class=\"wp-image-6506\" data-recalc-dims=\"1\" height=\"113\"></p>\n<p>Now, interestingly enough, this list fails to offer \u201cdoes not contain\u201d but that\u2019s fairly easy to work around. Since Xcode supports regex matching, you can easily replicate \u201cdoes not contain\u201d with an <a href=\"https://www.regextester.com/15\">appropriate regex</a>:</p>\n<p><a href=\"https://ericasadun.com/wp-content/uploads/2019/10/AntiMatch.tiff\"><img data-orig-file=\"https://ericasadun.com/wp-content/uploads/2019/10/AntiMatch.tiff\" data-orig-size=\"\" data-medium-file=\"https://ericasadun.com/wp-content/uploads/2019/10/AntiMatch.tiff\" data-attachment-id=\"6507\" data-image-meta=\"[]\" data-image-description=\"\" src=\"https://ericasadun.com/wp-content/uploads/2019/10/AntiMatch.tiff\" data-permalink=\"https://ericasadun.com/2019/10/27/fun-with-xcode-search-domains-excluding-match-text/antimatch/\" data-large-file=\"https://ericasadun.com/wp-content/uploads/2019/10/AntiMatch.tiff\" alt=\"\" data-image-title=\"AntiMatch\" data-comments-opened=\"1\" class=\"wp-image-6507\"></a></p>\n<p>Change the file name to a path to exclude source file directories.</p>\n<p>You can create as many search domains as you like. At least, I haven\u2019t found an upper bound yet. I haven\u2019t found a way to reorder the find scopes, although if you\u2019re really controlling about this, you can pop into \u00a0your workspace (<code>ProjectName.xcodeproj/project.xcworkspace/xcuserdata/username.xcuserdatad</code>), convert your <code>UserInterfaceState.xcuserstate</code> to xml (<code>plutil -convert xml1</code>), and hand-edit it the way you need.</p>\n<p>There are lots of wonderful little Xcode tweaks like these throughout this monster of an IDE. What are some of your faves? If I have time this week, I\u2019ll share some of mine, such as the four-square \u2014 another of my favorite tools \u2014 and a few great ways to connect your editor to the navigator.</p>"
|
|
},
|
|
"unread": false,
|
|
"readTime": 3406,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/66132046-6f14-488d-b590-8e93422723c8",
|
|
"label": "THree"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
}
|
|
],
|
|
"actionTimestamp": 1572499929438
|
|
},
|
|
{
|
|
"keywords": [
|
|
"Apple"
|
|
],
|
|
"originId": "https://9to5mac.com/?p=617536",
|
|
"recrawled": 1572455791719,
|
|
"updateCount": 1,
|
|
"fingerprint": "77224d8",
|
|
"id": "BmoAzSEWHFzR01wyxBZAhNEo11Vy8oDR1qKDe+tKVEQ=_16e1d065ad9:1c0f1:d4506071",
|
|
"author": "Michael Potuck",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "<div><img src=\"https://9to5mac.com/wp-content/uploads/sites/6/2019/10/sonos-discount-program-trade-in.jpeg?quality=82&strip=all&w=1600\"></div>\n<p>Sonos has announced a new initiative today that makes it easy for existing customers to trade in older Sonos products for a nice discount on new ones. For Apple customers, the <a href=\"http://www.anrdoezrs.net/links/9173227/type/dlg/https://www.sonos.com/en-us/tradeup\">Trade Up program</a> is a neat opportunity to bring <a href=\"http://www.anrdoezrs.net/links/9173227/type/dlg/https://www.sonos.com/en-us/products/wireless-speakers\">Sonos\u2019 AirPlay 2 compatible speakers</a> into your home.</p>\n<p> <a href=\"https://9to5mac.com/2019/10/30/sonos-trade-in-program-airplay-2/#more-617536\">more\u2026</a></p>\n<p>The post <a rel=\"nofollow\" href=\"https://9to5mac.com/2019/10/30/sonos-trade-in-program-airplay-2/\">Sonos pushing AirPlay 2 speaker lineup with new Trade Up program</a> appeared first on <a rel=\"nofollow\" href=\"https://9to5mac.com\">9to5Mac</a>.</p>"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://9to5mac.com/2019/10/30/sonos-trade-in-program-airplay-2/",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1572444986073,
|
|
"title": "Sonos pushing AirPlay 2 speaker lineup with new Trade Up program",
|
|
"published": 1572442686000,
|
|
"origin": {
|
|
"streamId": "feed/http://9to5mac.com/feed/",
|
|
"htmlUrl": "https://9to5mac.com",
|
|
"title": "9to5Mac"
|
|
},
|
|
"visual": {
|
|
"url": "https://cdn.vox-cdn.com/thumbor/06e5FJWgUfUSmDaPJIEZoGF1XOs=/0x68:2040x1136/fit-in/1200x630/cdn.vox-cdn.com/uploads/chorus_asset/file/10378819/DSCF3031.jpg",
|
|
"width": 1200,
|
|
"height": 628,
|
|
"contentType": "image/jpeg"
|
|
},
|
|
"unread": false,
|
|
"readTime": 4493,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/5ca4d61d-e55d-4999-a8d1-c3b9d8789815",
|
|
"label": "Macintosh"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
}
|
|
],
|
|
"actionTimestamp": 1572499889443
|
|
},
|
|
{
|
|
"originId": "tag:blogger.com,1999:blog-8954608646904080796.post-4991449931465752891",
|
|
"fingerprint": "7d99be14",
|
|
"thumbnail": [
|
|
{
|
|
"url": "https://1.bp.blogspot.com/-rGjQOQb89a8/XbS25YYbgeI/AAAAAAAADUI/s8Q4e0pTtX4qSTP3wrkt13VGV53Q8J0tQCLcBGAsYHQ/s72-c/092.jpg",
|
|
"width": 72,
|
|
"height": 72
|
|
}
|
|
],
|
|
"id": "v0v+7Ya8tssIZvd3/pcnFRr3HwvY/5YK3FGc2t65c0Y=_16e0a232509:17e32:d4506071",
|
|
"updated": 1572124724480,
|
|
"author": "Edward Feser",
|
|
"alternate": [
|
|
{
|
|
"href": "http://edwardfeser.blogspot.com/2019/10/john-paul-ii-in-defense-of-nation-and.html",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1572128105737,
|
|
"title": "John Paul II in defense of the nation and patriotism",
|
|
"published": 1572124680000,
|
|
"origin": {
|
|
"streamId": "feed/http://edwardfeser.blogspot.com/feeds/posts/default",
|
|
"htmlUrl": "http://edwardfeser.blogspot.com/",
|
|
"title": "Edward Feser"
|
|
},
|
|
"content": {
|
|
"direction": "ltr",
|
|
"content": "<br><div><a href=\"https://1.bp.blogspot.com/-rGjQOQb89a8/XbS25YYbgeI/AAAAAAAADUI/s8Q4e0pTtX4qSTP3wrkt13VGV53Q8J0tQCLcBGAsYHQ/s1600/092.jpg\"><img border=\"0\" data-original-height=\"180\" src=\"https://1.bp.blogspot.com/-rGjQOQb89a8/XbS25YYbgeI/AAAAAAAADUI/s8Q4e0pTtX4qSTP3wrkt13VGV53Q8J0tQCLcBGAsYHQ/s1600/092.jpg\" data-original-width=\"144\"></a></div><div><span>In chapters 11-15 of his last book <span><i><a href=\"https://www.amazon.com/Memory-Identity-Conversations-Dawn-Millennium/dp/0847827615/ref=sr_1_1?keywords=john+paul+II+memory+and+identity&qid=1572031154&sr=8-1\">Memory and Identity</a></i></span>, Pope St. John Paul II provides a lucid exposition of the idea of the nation as a natural social institution and of the virtue of patriotism, as these have been understood in traditional natural law theory and Catholic moral theology.\u00a0 The relevance to current controversies will be obvious.</span></div><div><span><br></span></div><div><span>What is the nation, and what is patriotism?<span>\u00a0 </span>John Paul begins by noting the connection between the nation and the family, where the former is in a sense an extension of the latter:</span></div><a name=\"more\"></a><br> <div><i><span>The Latin word </span></i><span>patria<i> is associated with the idea and the reality of \u201cfather\u201d (</i>pater<i>).<span>\u00a0 </span>The native land (or fatherland) can in some ways be identified with patrimony \u2013 that is, the totality of goods bequeathed to us by our forefathers\u2026 Our native land is thus our heritage and it is also the whole patrimony derived from that heritage.<span>\u00a0 </span>It refers to the land, the territory, but more importantly, the concept of patria includes the values and spiritual content that make up the culture of a given nation</i>. (p. 60)</span></div><div><span><br></span></div><div><span>As that last remark makes clear, the ties of blood are less important than those of culture.<span>\u00a0 </span>Indeed, multiple ethnicities can make up a nation.<span>\u00a0 </span>Referring to his native Poland, the pope notes that \u201cin ethnic terms, perhaps the most significant event for the foundation of the nation was the union of two great tribes,\u201d and yet other peoples too eventually went on together to comprise \u201cthe Polish nation\u201d (p. 77).<span>\u00a0 </span>It is shared culture, and especially a shared religion, that formed these diverse ethnicities into a nation:</span></div><div><span><br></span></div><div><i><span>When we speak of Poland\u2019s baptism, we are not simply referring to the sacrament of Christian initiation received by the first historical sovereign of Poland, but also to the event which was decisive for the birth of the nation and the formation of its Christian identity.<span>\u00a0 </span>In this sense, the date of Poland\u2019s baptism marks a turning point.<span>\u00a0 </span>Poland as a nation emerges from its prehistory at that moment and begins to exist in history</span></i><span>.<span>\u00a0 </span>(p. 77)</span></div><div><span><br></span></div><div><span>That a shared culture is the key to understanding the nation is a theme John Paul emphasizes repeatedly throughout the book.<span>\u00a0 </span>He says that \u201cevery nation draws life from the works of its own culture\u201d (p. 83), and that:</span></div><div><span><br></span></div><div><i><span>The nation is, in fact, the great community of men who are united by various ties, but above all, precisely by culture.<span>\u00a0 </span>The nation exists\u00a0<span>\u2018through\u2019 culture and \u2018for\u2019 culture\u00a0</span>and it is therefore the great educator of men in order that they may \u2018be more\u2019 in the community\u2026</span></i></div><div><i><span><br></span></i></div><div><i><span>I am the son of a nation which\u2026 has kept its identity, and it has kept, in spite of partitions and foreign occupations, its national sovereignty, not by relying on the resources of physical power but solely\u00a0<span>by relying on its culture. </span><span>\u00a0</span>This culture turned out, under the circumstances, to be more powerful than all other forces.<span>\u00a0 </span>What I say here concerning the right of the nation to the foundation of its culture and its future is not, therefore, the echo of any \u2018nationalism\u2019, but it is always a question of a stable element of human experience and of the\u00a0<span>humanistic perspective of man's development.<span>\u00a0 </span></span>There exists a fundamental sovereignty of society, which is manifested in the culture of the nation</span></i><span>. (p. 85)</span></div><div><span><br></span></div><div><span>In addition to shared values and religion, John Paul identifies shared history as another crucial aspect of a nation\u2019s identifying culture:</span></div><div><span><br></span></div><div><i><span>Like individuals, then, nations are endowed with historical memory\u2026 And the histories of nations, objectified and recorded in writing, are among the essential elements of culture \u2013 the element which determines the nation\u2019s identity in the temporal dimension</span></i><span>.<span>\u00a0 </span>(pp. 73-74)</span></div><div><span><br></span></div><div><span>The pope notes that citizens of modern Western European countries often have \u201creservations\u201d about the notion of \u201cnational identity as expressed through culture,\u201d and have even \u201carrived at a stage which could be defined as \u2018post-identity\u2019\u201d (p. 86).<span>\u00a0 </span>There is \u201ca widespread tendency to move toward supranational structures, even internationalism\u201d with \u201csmall nations\u2026 allow[ing] themselves to be absorbed into larger political structures\u201d (p. 66).<span>\u00a0 </span>However, the disappearance of the nation would be contrary to the natural order of things:</span></div><div><span><br></span></div><div><i><span>Yet it still seems that nation and native land, like the family, are permanent realities.<span>\u00a0 </span>In this regard, Catholic social doctrine speaks of \u201cnatural\u201d societies, indicating that both the family and the nation have a particular bond with human nature, which has a social dimension.<span>\u00a0 </span>Every society\u2019s formation takes place in and through the family: of this there can be no doubt.<span>\u00a0 </span>Yet something similar could also be said about the nation</span></i><span>. (p. 67)</span></div><div><span><br></span></div><div><span>And again:</span></div><div><span><br></span></div><div><i><span>The term \u201cnation\u201d designates a community based in a given territory and distinguished from other nations by its culture.<span>\u00a0 </span>Catholic social doctrine holds that the family and the nation are both natural societies, not the product of mere convention.<span>\u00a0 </span>Therefore, in human history they cannot be replaced by anything else.<span>\u00a0 </span>For example, the nation cannot be replaced by the State, even though the nation tends naturally to establish itself as a State\u2026 Still less is it possible to identify the nation with so-called democratic society, since here it is a case of two distinct, albeit interconnected orders.<span>\u00a0 </span>Democratic society is closer to the State than is the nation.<span>\u00a0 </span>Yet the nation is the ground on which the State is born</span></i><span>. (pp. 69-70)</span></div><div><span><br></span></div><div><span>As this last point about the state and democracy indicates, a nation cannot be defined in terms of, or replaced by, either governmental institutions and their laws and policies on the one hand, or the aggregate of the attitudes of individual citizens on the other.<span>\u00a0 </span>It is something deeper than, and presupposed by, both of these things.<span>\u00a0 </span>It is only insofar as a nation, defined by its culture, is already in place that a polity can come into being.<span>\u00a0 </span>Hence it is a mistake to think that, if the common cultural bonds that define a nation disappear, the nation can still be held together by virtue of governmental policy either imposed from above or arrived at my majority vote.<span>\u00a0 </span>For a people have to be united by common bonds of culture before they can all see either governmental policy or the will of the majority as legitimate.<span>\u00a0 </span>(Readers familiar with the work of Roger Scruton will note the parallels, and how deeply conservative John Paul II\u2019s understanding of the nation is.)<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span>Now, as a natural institution, the nation, like the family, is necessary for our well-being.<span>\u00a0 </span>And as with the family, this entails a <i>moral duty</i> to be loyal to and to defend one\u2019s nation \u2013 and for precisely the same sorts of reasons one has a duty of loyalty to and defense of one\u2019s family:</span></div><div><span><br></span></div><div><i><span>If we ask where patriotism appears in the Decalogue, the reply comes without hesitation: it is covered by the fourth commandment, which obliges us to honor our father and mother.<span>\u00a0 </span>It is included under the umbrella of the Latin word </span></i><span>pietas<i>, which underlines the religious dimension of the respect and veneration due to parents\u2026</i></span></div><div><span><i><br></i></span></div><div><i><span>Patriotism is a love for everything to do with our native land: its history, its traditions, its language, its natural features.<span>\u00a0 </span>It is a love which extends also to the works of our compatriots and the fruits of their genius.<span>\u00a0 </span>Every danger that threatens the overall good of our native land becomes an occasion to demonstrate this love</span></i><span>. (pp. 65-66)</span></div><div><span><br></span></div><div><span>Among the dangers to the nation are the opposite extreme economic errors of egalitarian statism and liberal individualism, which threaten to destroy the common culture that defines the nation \u2013 in the one case from the top down and in the other from the bottom up.<span>\u00a0 </span>The pope writes:</span></div><div><span><br></span></div><div><i><span>[W]e must ask how best to respect the proper relationship between economics and culture without destroying this greater human good for the sake of profit, in deference to the overwhelming power of one-sided market forces.<span>\u00a0 </span>It matters little, in fact, whether this kind of tyranny is imposed by Marxist totalitarianism or by Western liberalism</span></i><span>. (pp. 83-84)</span></div><div><span><br></span></div><div><span>If liberal individualism is an error that pays insufficient respect to the nation, there is of course an opposite extreme error which involves giving excessive esteem to the nation \u2013 namely, nationalism.<span>\u00a0 </span>Patriotism, rightly understood, is the middle ground between these extremes:</span></div><div><span><br></span></div><div><i><span>Whereas nationalism involves recognizing and pursuing the good of one\u2019s own nation alone, without regard for the rights of others, patriotism, on the other hand, is a love for one\u2019s native land that accords rights to all other nations equal to those claimed for one\u2019s own</span></i><span>. (p. 67)</span></div><div><span><br></span></div><div><span>John Paul II was clear that the remedy for nationalism was not to go to the opposite extreme (whether in the name of individualism, internationalism, or whatever), but rather precisely to insist on the sober middle ground:</span></div><div><span><br></span></div><div><i><span>How can we be delivered from such a danger?<span>\u00a0 </span>I think the right way is through patriotism\u2026 Patriotism, in other words, leads to a properly ordered social love</span></i><span>. (p. 67)</span></div><div><span><br></span></div><div><span>Now, let\u2019s note a number of things about these remarks and their implications.<span>\u00a0 </span>First, as I have said, what the late pope was giving expression to here is not merely his personal opinion, but traditional natural law political philosophy and Catholic moral teaching \u2013 the kind of thing that would have been well known to someone formed in Thomistic philosophy and theology in the early twentieth century, as John Paul II was.</span></div><div><span><br></span></div><div><span>Second, John Paul\u2019s teaching implies that those who seek to preserve their nation\u2019s common culture, and for that reason are concerned about trends that might radically alter its religious makeup or undermine its common language and reverence for its history, are simply following a natural and healthy human impulse and indeed following out the implications of the fourth commandment.<span>\u00a0 </span>There is no necessary connection between this attitude and racism, hatred for immigrants, religious bigotry, or the like.<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span>Of course, a person who seeks to preserve his nation\u2019s culture <i>might</i> also be a racist or xenophobe or bigot.<span>\u00a0 </span>The point, however, is that he <i>need not</i> be, and indeed that it is wrong even to <i>presume</i> that he is, because a special love for one\u2019s own nation and desire to preserve its culture is a natural human tendency, and thus likely to be found even in people who have no racist or xenophobic or bigoted attitudes at all.<span>\u00a0 </span>Indeed, it is, again, even morally virtuous.<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span>Needless to say, there is <i>also</i> a moral need to balance this patriotism with a welcoming attitude toward immigrants, with respect for the rights of religious minorities, and so forth.<span>\u00a0 </span>The point, however, is that <i>all </i>of these things need to be balanced. <span>\u00a0</span>Too many contemporary Catholics, including some churchmen, have a tendency to emphasize only the latter while ignoring the former.<span>\u00a0 </span>They have a tendency to buy into the leftist narrative according to which the current wave of populist and patriotic sentiment in the United States and Western Europe is merely an expression of racism and xenophobia.<span>\u00a0 </span>This is deeply unjust, contrary to Catholic teaching, and politically dangerous.<span>\u00a0 </span>It is unjust and contrary to Catholic teaching because, again, both natural law and traditional moral theology affirm that a desire to preserve one\u2019s nation and its culture are natural human sentiments and morally praiseworthy.<span>\u00a0 </span>It is dangerous because, when governing authorities fail to respect and take account of these natural and decent human sentiments, they are <i>inviting</i> rather than preventing a nationalist overreaction. </span></div><div><span><br></span></div><div><span>(President Trump has famously called himself a \u201cnationalist,\u201d which is unfortunate given the connotations of that term.<span>\u00a0 </span>However, from <span><a href=\"https://www.nbcnews.com/politics/donald-trump/future-does-not-belong-globalists-trump-pushes-nationalism-u-n-n1058171\">his 2019 address to the United Nations</a></span> it seems clear that what he means by this is just the defense of the institution of the nation against those who would dissolve it in the name of globalism, open borders, etc.<span>\u00a0 </span>Moreover, he explicitly affirmed the right of <i>every</i> nation to preserve itself and its sovereignty, and the right of <i>every</i>human being to have a special patriotic love and preference for his own country.<span>\u00a0 </span>He also has repeatedly called for the United States to refrain from intervening in the affairs of other nations.<span>\u00a0 </span>So it is evident that it is really just <i>patriotism</i> in the sense described above, rather than some sort of American nationalism, that he intends to promote.)</span></div><div><span><br></span></div><div><span>The current controversy over illegal immigration must be understood in light of these principles.<span>\u00a0 </span>In <span><a href=\"http://w2.vatican.va/content/john-paul-ii/en/messages/migration/documents/hf_jp-ii_mes_25071995_undocumented_migrants.html\">a 1996 message on World Migration Day</a></span>, John Paul II emphasized the need to welcome migrants, to take account of the dangerous circumstances they are sometimes fleeing, to avoid all racist and xenophobic attitudes, and so on.<span>\u00a0 </span>At the same time, he acknowledged that \u201cmigration is assuming the features of a social emergency, above all because of the increase in\u00a0<i>illegal migrants\u201d</i><span> (emphasis in the original), and that the problem is</span> \u201cdelicate and complex.\u201d<span>\u00a0 </span>He affirmed that \u201cillegal immigration should be prevented\u201d and that one reason it is problematic is that \u201cthe supply of foreign labour is becoming excessive in comparison to the needs of the economy, which already has difficulty in absorbing its domestic workers.\u201d<span>\u00a0 </span>And he stated that in some cases, it may be necessary to advise migrants \u201cto seek acceptance in other countries, or to return to their own country.\u201d</span></div><div><span><br></span></div><div><span>The Catechism promulgated by Pope John Paul II <span><a href=\"http://www.vatican.va/archive/ccc_css/archive/catechism/p3s2c2a4.htm\">teaches that</a></span>:</span></div><div><span><br></span></div><div><i><span>The more prosperous nations are obliged, <b>to the extent they are able,</b>to welcome the\u00a0<span>foreigner\u00a0</span>in search of the security and the means of livelihood which he cannot find in his country of origin. Public authorities should see to it that the natural right is respected that places a guest under the protection of those who receive him.</span></i></div><div><i><span><br></span></i></div><div><b><i><span>Political authorities, for the sake of the common good for which they are responsible,</span></i></b><i><span> <b>may make the exercise of the right to immigrate subject to various juridical conditions,</b> especially with regard to the immigrants' duties toward their country of adoption. <b>Immigrants are obliged to respect with gratitude the material and spiritual heritage of the country that receives them, to obey its laws and to assist in carrying civic burdens</b></span></i><b><span>.</span></b><span><span>\u00a0 </span>(Emphasis added)</span></div><div><span><br></span></div><div><span>End quote.<span>\u00a0 </span>Note that the Catechism teaches that immigrants have a <i>duty</i> to respect the laws and \u201cspiritual heritage\u201d of the nation they seek to enter, and that political authorities may restrict immigration so as to uphold the \u201ccommon good\u201d of the nation they govern.<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span>Hence, there is no foundation in Catholic teaching for an open borders position, or for the position that those who seek to uphold the common culture and economic interests of their nation ought to be dismissed as racists and xenophobes.<span>\u00a0 </span>On the contrary, Catholic teaching <i>explicitly rules out</i> those positions.<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span>There is a further implication of John Paul II\u2019s teaching.<span>\u00a0 </span>It isn\u2019t merely that having a special love for one\u2019s nation and its culture is natural and virtuous.<span>\u00a0 </span>It is that a <i>failure </i>to have it is <i>vicious</i> \u2013 a violation of the fourth commandment.</span></div><div><span><br></span></div><div><span>Of course, every nation has its faults, and aspects of its history of which one ought to be ashamed.<span>\u00a0 </span>For example, Germans are right to repudiate the Nazi period of their history, and Americans are right to repudiate slavery and segregation.<span>\u00a0 </span>But there is a mentality prevalent in the modern West that goes well beyond that \u2013 that insists on seeing nothing but evil in one\u2019s own nation and its culture and history.<span>\u00a0 </span>This is the mentality <span><a href=\"https://quillette.com/2019/10/07/oikophobia-our-western-self-hatred/\">sometimes called <i>oikophobia</i></a></span> \u2013 the hatred of one\u2019s own \u201chousehold\u201d (<i>oikos</i>), in the sense of one\u2019s own nation.<span>\u00a0 </span>One sees this mentality in Westerners who shrilly and constantly denounce their civilization as irredeemably racist, colonialist, etc., downplaying or denying its virtues, and comparing it unfavorably to other cultures \u2013 as if Western culture is somehow <i>more</i> prone to such failings than other cultures are, and as if it hasn\u2019t contributed enormously to the good of the world (both of which are absurd suppositions).</span></div><div><span><br></span></div><div><span>Oikophobia is <i>evil</i>.<span>\u00a0 </span>It is a spiritual poison that damages both those prone to it (insofar as it makes them bitter, ungrateful, etc.) and the social order of which they are parts (insofar as it undermines the love and loyalty citizens need to have for their nation if it is to survive).<span>\u00a0 </span>It is analogous to the evil of hating and undermining one\u2019s own family.<span>\u00a0 </span>It is a violation of the fourth commandment.</span></div><div><span><br></span></div><div><span>The oikophobe sees his position as a remedy for nationalism, but in fact he is simply guilty of falling into an error that is the opposite extreme from that of the nationalist.<span>\u00a0 </span>Moreover, he is inadvertently <i>promoting</i> nationalism, because human beings have a tendency to overreact to one extreme by going too far in the other direction.<span>\u00a0 </span>Nationalism is bound to arise precisely as an overreaction against oikophobia.<span>\u00a0 </span>Those who are currently reacting to what they perceive as a resurgent nationalism by doubling down on oikophobia \u2013 pushing for open borders, indiscriminately denouncing their opponents as racists and xenophobes, etc. \u2013 are making a true nationalist backlash <i>more </i>likely, not less likely.<span>\u00a0 </span>The only true remedy for the evils of nationalism and oikophobia is, as John Paul II taught, the sober middle ground of patriotism.</span></div><div><span><br></span></div><div><span>It is no accident that those prone to oikophobia tend to be precisely the same people as those who want to push further the sexual revolution, feminism, and the destruction of the traditional family and traditional sex roles that these entail.<span>\u00a0 </span>The same liberal individualist poison is at the core of all of these attitudes.<span>\u00a0 </span>As St. John Paul II said, \u201c<i>patria </i>is associated with the idea and the reality of \u2018father\u2019 (<i>pater</i>).\u201d<span>\u00a0 </span>Hatred of masculinity and of the paternal authority and responsibilities that are its fulfilment, hatred of the traditional family and of the sexual morality that safeguards it, and hatred of one\u2019s fatherland, are ultimately of a piece.<span>\u00a0 </span>And lurking beneath them all is a deeper hatred for another, heavenly Father.</span></div><div><span><br></span></div><div><span>Further reading:</span></div><div><span><br></span></div><div><span><span><a href=\"https://edwardfeser.blogspot.com/2017/10/liberty-equality-fraternity.html\">Liberty, equality, fraternity?</a></span></span><span></span></div><div><span><br></span></div><div><span><span><a href=\"http://edwardfeser.blogspot.com/2019/06/continetti-on-post-liberal-conservatism_2.html\">Continetti on post-liberal conservatism</a></span></span><span></span></div><div><span><br></span></div><div><span><span><a href=\"https://www.claremont.org/crb/article/hayeks-tragic-capitalism/\">Hayek\u2019s Tragic Capitalism</a></span></span></div>"
|
|
},
|
|
"visual": {
|
|
"url": "none"
|
|
},
|
|
"unread": true,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/5ca4d61d-e55d-4999-a8d1-c3b9d8789815",
|
|
"label": "Macintosh"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/fbdcd69b-7e27-4b6a-bfed-6584b944155d",
|
|
"label": "\ud83e\udd1e\ud83c\udffb\ud83e\udd1e\ud83c\udffb\ud83e\udd1e\ud83c\udffb"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
}
|
|
],
|
|
"actionTimestamp": 1572499824479
|
|
},
|
|
{
|
|
"originId": "https://www.raywenderlich.com/5436806-modern-collection-views-with-compositional-layouts",
|
|
"fingerprint": "16268498",
|
|
"id": "RFlzskW4NhJjlZfijOSI8IXqM9+zz6V9qnDVl1gxaJs=_16e1cddfaa1:1c015:d4506071",
|
|
"updated": 1572440368000,
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "In this tutorial, you\u2019ll learn how to build beautiful, modern UICollectionView layouts using iOS 13\u2019s new declarative UICollectionViewCompositionalLayout API."
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://www.raywenderlich.com/5436806-modern-collection-views-with-compositional-layouts",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1572442340001,
|
|
"title": "Modern Collection Views with Compositional Layouts [FREE]",
|
|
"published": 1572440368000,
|
|
"origin": {
|
|
"streamId": "feed/http://www.raywenderlich.com/feed",
|
|
"htmlUrl": "http://www.raywenderlich.com/feed",
|
|
"title": "Ray Wenderlich | High quality programming tutorials: iOS, Android, Swift, Kotlin, Unity, and more"
|
|
},
|
|
"unread": false,
|
|
"readTime": 3593,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/885f2e01-d314-4e63-abac-17dcb063f5b5",
|
|
"label": "Programming"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
}
|
|
],
|
|
"actionTimestamp": 1572499811331
|
|
},
|
|
{
|
|
"originId": "https://inessential.com/2019/10/30/etas_follow_up",
|
|
"fingerprint": "d48dc2d2",
|
|
"id": "+jHfsXnBCVfCstSIW1WDumAyigT4rnsUPnI5WFxgnAU=_16e1e5e8e9e:1ca95:d4506071",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "<p>Some people took my post <a href=\"https://inessential.com/2019/10/28/no_etas\">No ETAs</a> as if I were arguing against doing software estimates of any kind, ever.</p>\n<p>I didn\u2019t actually mean that. If your boss, project manager, or person you\u2019re contracting with asks for an estimate, do your best to come up with something accurate. If you\u2019re writing enterprise software, you may even be contractually bound to provide estimates for when features will ship.</p>\n<p>There are ways to get pretty good at this. Pay attention to history and avoid wishful thinking. Don\u2019t assume perfect productivity. Allow for the unexpected, because there\u2019s always something.</p>\n<p>What I\u2019m talking about is the case where you\u2019re writing a consumer-facing app \u2014\u00a0something that would get published on an app store, for instance \u2014\u00a0and customers or potential customers ask about an ETA for a given feature. Don\u2019t do it! (For the reasons stated in the article.)</p>"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://inessential.com/2019/10/30/etas_follow_up",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1572467543710,
|
|
"title": "ETAs: Follow-Up",
|
|
"published": 1572466202000,
|
|
"origin": {
|
|
"streamId": "feed/http://ranchero.com/xml/rss.xml",
|
|
"htmlUrl": "https://inessential.com/",
|
|
"title": "inessential.com"
|
|
},
|
|
"unread": false,
|
|
"readTime": 6552,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/66132046-6f14-488d-b590-8e93422723c8",
|
|
"label": "THree"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
}
|
|
],
|
|
"actionTimestamp": 1572499788300
|
|
},
|
|
{
|
|
"keywords": [
|
|
"Apple"
|
|
],
|
|
"originId": "https://9to5mac.com/?p=617593",
|
|
"fingerprint": "a1dafaae",
|
|
"id": "BmoAzSEWHFzR01wyxBZAhNEo11Vy8oDR1qKDe+tKVEQ=_16e1de23321:1c6e3:d4506071",
|
|
"author": "Guilherme Rambo",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "<div><img src=\"https://9to5mac.com/wp-content/uploads/sites/6/2019/10/16-inch-macbook-pro-touch-bar-keyboard.jpg?quality=82&strip=all&w=1600\"></div>\n<p>Rumors about a new 16-inch MacBook Pro are not exactly new, with recent icon evidence found in macOS Catalina betas suggesting the redesign mentioned in some reports is not going to happen as we thought.</p>\n<p> <a href=\"https://9to5mac.com/2019/10/30/exclusive-16-inch-macbook-pro-touch-bar-and-touch-id-layout-confirmed/#more-617593\">more\u2026</a></p>\n<p>The post <a rel=\"nofollow\" href=\"https://9to5mac.com/2019/10/30/exclusive-16-inch-macbook-pro-touch-bar-and-touch-id-layout-confirmed/\">Exclusive: 16-inch MacBook Pro Touch Bar and Touch ID layout confirmed</a> appeared first on <a rel=\"nofollow\" href=\"https://9to5mac.com\">9to5Mac</a>.</p>"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://9to5mac.com/2019/10/30/exclusive-16-inch-macbook-pro-touch-bar-and-touch-id-layout-confirmed/",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1572459393825,
|
|
"title": "Exclusive: 16-inch MacBook Pro Touch Bar and Touch ID layout confirmed",
|
|
"published": 1572456327000,
|
|
"origin": {
|
|
"streamId": "feed/http://9to5mac.com/feed/",
|
|
"htmlUrl": "https://9to5mac.com",
|
|
"title": "9to5Mac"
|
|
},
|
|
"unread": false,
|
|
"readTime": 3947,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/5ca4d61d-e55d-4999-a8d1-c3b9d8789815",
|
|
"label": "Macintosh"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
}
|
|
],
|
|
"actionTimestamp": 1572499186128
|
|
},
|
|
{
|
|
"originId": "https://inessential.com/2019/10/30/you_choose_follow_up",
|
|
"fingerprint": "f1dd63ab",
|
|
"id": "+jHfsXnBCVfCstSIW1WDumAyigT4rnsUPnI5WFxgnAU=_16e1f71bf1c:1d086:d4506071",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "<p>It came to my attention after writing my blog post about how <a href=\"https://inessential.com/2019/10/29/you_choose\">we choose the web we want</a>\u00a0that the pessimism is about not being able to make a living from blogging.</p>\n<p>Here\u2019s my followup: I don\u2019t care. Bite me.</p>"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://inessential.com/2019/10/30/you_choose_follow_up",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1572485578524,
|
|
"title": "You Choose: Follow-Up",
|
|
"published": 1572482100000,
|
|
"origin": {
|
|
"streamId": "feed/http://ranchero.com/xml/rss.xml",
|
|
"htmlUrl": "https://inessential.com/",
|
|
"title": "inessential.com"
|
|
},
|
|
"unread": false,
|
|
"readTime": 3663,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/66132046-6f14-488d-b590-8e93422723c8",
|
|
"label": "THree"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
}
|
|
],
|
|
"actionTimestamp": 1572499146275
|
|
},
|
|
{
|
|
"originId": "https://inessential.com/2019/10/14/netnewswire_os_compatibility_strategy",
|
|
"fingerprint": "fa6e6fff",
|
|
"id": "+jHfsXnBCVfCstSIW1WDumAyigT4rnsUPnI5WFxgnAU=_16dccdfc972:a6e5:d4506071",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "<p>We have two goals with the app: 1) get as many people using RSS as possible, and 2) make the best app we can.</p>\n<p>To reach #2 \u2014\u00a0making the best app we can \u2014\u00a0we need to do a couple things. One is stay modern: use new APIs and tools that make the app better and easier to maintain. A second is to not spend time on things that don\u2019t make the app better. A third is to attract and retain contributors, who are usually more psyched to work with modern stuff than with old stuff.</p>\n<p>You can see how that\u2019s in a little bit of conflict with #1 (getting as many people as possible using RSS readers).</p>\n<h4>Here\u2019s the plan</h4>\n<p>After a major OS update, we will switch to requiring that update on our next major release \u2014\u00a0where major is defined as something like 5.0 or 5.1, but not something like 5.0.1. (In other words: the upcoming NetNewsWire 5.0.3 release will run on Mojave, while NetNewsWire 5.1 will require Catalina.)</p>\n<p>At the same time, we will make older versions available via the website. For instance, the last version that will run on Mojave will likely be 5.0.4 (which isn\u2019t finished yet) \u2014 and we\u2019ll make that version available indefinitely for people who haven\u2019t upgraded to Catalina.</p>\n<p>This will mean that people running older OSes will still get a high-quality app \u2014 it\u2019s just that it won\u2019t have the latest features.</p>\n<p>The key is that this allows us to make NetNewsWire the best app it can be, and making the best app we can is also part of furthering the goal of getting as many people as possible using RSS. (The biggest part, in fact. Bigger than compatibility with older OSes.)</p>\n<p>While I know this will disappoint some people, I hope you\u2019ll understand <em>why</em> we decided to do it this way. Decisions like this are never easy \u2014 there are always conflicting values to weigh, pros and cons and add up \u2014\u00a0and we don\u2019t make them impulsively. But making NetNewsWire the best app it can be has to be job #1.</p>"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://inessential.com/2019/10/14/netnewswire_os_compatibility_strategy",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1571100281202,
|
|
"title": "NetNewsWire OS Compatibility Strategy",
|
|
"published": 1571099404000,
|
|
"origin": {
|
|
"streamId": "feed/http://ranchero.com/xml/rss.xml",
|
|
"htmlUrl": "https://inessential.com/",
|
|
"title": "inessential.com"
|
|
},
|
|
"unread": false,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/66132046-6f14-488d-b590-8e93422723c8",
|
|
"label": "THree"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
}
|
|
],
|
|
"actionTimestamp": 1571123677415
|
|
},
|
|
{
|
|
"keywords": [
|
|
"Xcode"
|
|
],
|
|
"originId": "https://nshipster.com/swiftui-previews",
|
|
"recrawled": 1571407228188,
|
|
"updateCount": 2,
|
|
"fingerprint": "7582ddff",
|
|
"id": "08l+9ftpGejQ9f/2DZ6dom5rSnNJJO9OCox6I3nUnWg=_16dc8d7749a:96ed:d4506071",
|
|
"updated": 1571036400000,
|
|
"author": "Mattt",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "<p>Working on a large iOS codebase often involves a lot of waiting. But with Xcode 11, our wait is finally over \u2014 and it\u2019s all thanks to SwiftUI.</p>"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://nshipster.com/swiftui-previews/",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1571032626330,
|
|
"title": "SwiftUI Previews on macOS Catalina and Xcode 11",
|
|
"published": 1571036400000,
|
|
"origin": {
|
|
"streamId": "feed/http://nshipster.com/feed.xml",
|
|
"htmlUrl": "https://nshipster.com/",
|
|
"title": "NSHipster"
|
|
},
|
|
"content": {
|
|
"direction": "ltr",
|
|
"content": "<p>Working on a large iOS codebase often involves a lot of waiting:\nWaiting for Xcode to index your files,\nwaiting for Swift and Objective-C code to compile,\nwaiting for the Simulator to boot and your app to launch\u2026</p>\n<p>And after all of that,\nyou spend even more time getting your app\ninto a particular state and onto a particular screen,\njust to see whether the Auto Layout constraint you just added\nfixes that regression you found.\nIt didn\u2019t, of course,\nso you jump back into Xcode,\ntweak the Content Hugging Priority,\nhit <kbd>\u2318</kbd><kbd>R</kbd>,\nand start the whole process again.</p>\n<p>We might relate our sorry predicament to\n<a rel=\"noopener noreferrer\" href=\"https://xkcd.com/303/\">that one xkcd comic</a>,\nbut for those of us who don\u2019t so much relish in\nthe stop-and-go nature of app development,\nthere\u2019s an old Yiddish joke about Shlemiel the painter\n<em>(provided below with a few \uf8ff-specific modifications;\nfor the uninitiated,\nplease refer to Joel Spolsky\u2019s\n<a rel=\"noopener noreferrer\" href=\"https://www.joelonsoftware.com/2001/12/11/back-to-basics/\">original telling</a>)</em>:</p>\n<blockquote>\n<p>Shlemiel gets a job as a software developer,\nimplementing a new iOS app.\nOn the first sprint he opens Xcode\nand implements 10 new screens of the app.\n<em>\u201cThat\u2019s pretty good!\u201d</em> says his manager,\n<em>\u201cyou\u2019re a fast worker!\u201d</em> and pays him a Bitcoin.</p>\n<p>The next sprint Shlemiel only gets 5 screens done.\n<em>\u201cWell, that\u2019s not nearly as good as yesterday,\nbut you\u2019re still a fast worker. 5 screens is respectable,\u201d</em>\nand pays him a Bitcoin.</p>\n<p>The next sprint Shlemiel implements 1 screen.\n<em>\u201cOnly 1!\u201d</em> shouts his manager.\n<em>\u201cThat\u2019s unacceptable!\nOn the first day you did ten times that much work!\nWhat\u2019s going on?\u201d</em></p>\n<p><em>\u201cI can\u2019t help it,\u201d</em> says Shlemiel.\n<em>\u201cEach sprint I get further and further away from\n<code>application(_:did<wbr>Finish<wbr>Launching<wbr>With<wbr>Options:)</code>!\u201d</em></p>\n</blockquote>\n<p>Over the years,\nthere have been some developments that\u2019ve helped things slightly,\nincluding\n<a href=\"https://nshipster.com/ibinspectable-ibdesignable/\"><code>@IBInspectable</code> and <code>@IBDesignable</code></a>\nand <a href=\"https://nshipster.com/xcplayground/\">Xcode Playgrounds</a>.\nBut with Xcode 11,\nour wait is finally over \u2014\nand it\u2019s all thanks to SwiftUI.</p>\n<hr>\n<aside>\n<p>The functionality described in this article requires the following:</p>\n<ul>\n<li><strong>Xcode 11</strong></li>\n<li><strong>macOS Catalina</strong></li>\n<li>\n<strong>iOS 13</strong> set as the <strong>Deployment Target</strong> for your app\u2019s <strong>Debug</strong> configuration <br>\n<em>(In Xcode, navigate your project\u2019s Build Settings;\nunder the Deployment heading,\nexpand the iOS Deployment Target setting and set Debug to iOS 13.0 or later)</em>\n</li>\n</ul>\n<p>Without these three things,\nyour code either won\u2019t compile or won\u2019t render live previews.</p>\n</aside>\n<hr>\n<p>Although many of us have taken a <a href=\"https://nshipster.com/wwdc-2019/\"><em>\u201cwait and see\u201d</em> approach</a> to SwiftUI,\nwe can start using its capabilities <strong>today</strong>\nto radically speed up and improve our development process \u2014\n<em>without changing a line of code in our UIKit apps</em>.</p>\n<p>Consider a subclass of <code>UIButton</code>\nthat draws a border around itself:</p>\n<pre data-lang=\"Swift\"><code><span>final</span> <span>class</span> <span>Bordered<wbr>Button</span><span>:</span> <span>UIButton</span> <span>{</span>\n <span>var</span> <span>corner<wbr>Radius</span><span>:</span> <span>CGFloat</span> <span>{</span> <var>...</var> <span>}</span>\n <span>var</span> <span>border<wbr>Width</span><span>:</span> <span>CGFloat</span> <span>{</span> <var>...</var> <span>}</span>\n <span>var</span> <span>border<wbr>Color</span><span>:</span> <span>UIColor</span><span>?</span> <span>{</span> <var>...</var> <span>}</span>\n <span>}</span>\n </code></pre>\n<p>Normally,\nif we wanted to test how our UI element performs,\nwe\u2019d have to add it to a view in our app,\nbuild and run,\nand navigate to that screen.\nBut with Xcode 11,\nwe can now see a preview side-by-side with the code editor\nby adding the following under the original declaration of <code>Bordered<wbr>Button</code>:</p>\n<div>\n<pre data-lang=\"Swift\"><code><span>#if can<wbr>Import(Swift<wbr>UI) && DEBUG</span>\n <span>import</span> <span>Swift<wbr>UI</span>\n <span>@available(i<wbr>OS 13.0, *)</span>\n <span>struct</span> <span>Bordered<wbr>Button_Preview</span><span>:</span> <span>Preview<wbr>Provider</span> <span>{</span>\n <span>static</span> <span>var</span> <span>previews</span><span>:</span> <span>some</span> <span>View</span> <span>{</span>\n <span>UIView<wbr>Preview</span> <span>{</span>\n <span>let</span> <span>button</span> <span>=</span> <span>Bordered<wbr>Button</span><span>(</span><span>frame</span><span>:</span> <span>.</span><span>zero</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Title</span><span>(</span><span>"Follow"</span><span>,</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>tint<wbr>Color</span> <span>=</span> <span>.</span><span>system<wbr>Orange</span>\n <span>button</span><span>.</span><span>set<wbr>Title<wbr>Color</span><span>(</span><span>.</span><span>system<wbr>Orange</span><span>,</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>return</span> <span>button</span>\n <span>}</span><span>.</span><span>preview<wbr>Layout</span><span>(</span><span>.</span><span>size<wbr>That<wbr>Fits</span><span>)</span>\n <span>.</span><span>padding</span><span>(</span><span>10</span><span>)</span>\n <span>}</span>\n <span>}</span>\n <span>#endif</span>\n </code></pre>\n<aside>\n<p><img alt=\"SwiftUI preview with Follow button\" src=\"https://nshipster.com/assets/swiftui-preview-follow-94a523cd048a0cd14d78414d55d238e9c57abd3ed7ea30dd9a6fb73facc05d78.png\"></p>\n</aside>\n</div>\n<p>Using a new feature called <dfn>dynamic replacement</dfn>,\nXcode can update this preview without recompiling \u2014\nwithin moments of your making a code change.\nThis lets you rapidly prototype changes like never before.</p>\n<p>Want to see how your button handles long titles?\nBang away on your keyboard within the call to <code>set<wbr>Title(_:for:)</code>\nin your preview,\nand test out potential fixes in your underlying implementation\nwithout so much as leaving your current file!</p>\n<aside>\n<p><code>UIView<wbr>Preview</code> is a custom, generic structure\nthat we created to conveniently host previews of <code>UIView</code> subclasses.\nFeel free to <a rel=\"noopener noreferrer\" href=\"https://gist.github.com/mattt/ff6b58af8576c798485b449269d43607\">download the source</a>\nand add it to your project directly.</p>\n<p>Incorporating a proper dependency would be complicated by\nthe conditional import and iOS 13 Deployment Target settings\nrequired to make Xcode Previews work for non-SwiftUI apps,\nso in this particular instance,\nwe think it\u2019s best to embed these files directly.</p>\n<details>\n\n<pre data-lang=\"Swift\"><code><span>import</span> <span>UIKit</span>\n <span>#if can<wbr>Import(Swift<wbr>UI) && DEBUG</span>\n <span>import</span> <span>Swift<wbr>UI</span>\n <span>struct</span> <span>UIView<wbr>Preview</span><span><</span><span>View</span><span>:</span> <span>UIView</span><span>></span><span>:</span> <span>UIView<wbr>Representable</span> <span>{</span>\n <span>let</span> <span>view</span><span>:</span> <span>View</span>\n <span>init</span><span>(</span><span>_</span> <span>builder</span><span>:</span> <span>@escaping</span> <span>()</span> <span>-></span> <span>View</span><span>)</span> <span>{</span>\n <span>view</span> <span>=</span> <span>builder</span><span>()</span>\n <span>}</span>\n <span>// MARK: - UIView<wbr>Representable</span>\n <span>func</span> <span>make<wbr>UIView</span><span>(</span><span>context</span><span>:</span> <span>Context</span><span>)</span> <span>-></span> <span>UIView</span> <span>{</span>\n <span>return</span> <span>view</span>\n <span>}</span>\n <span>func</span> <span>update<wbr>UIView</span><span>(</span><span>_</span> <span>view</span><span>:</span> <span>UIView</span><span>,</span> <span>context</span><span>:</span> <span>Context</span><span>)</span> <span>{</span>\n <span>view</span><span>.</span><span>set<wbr>Content<wbr>Hugging<wbr>Priority</span><span>(</span><span>.</span><span>default<wbr>High</span><span>,</span> <span>for</span><span>:</span> <span>.</span><span>horizontal</span><span>)</span>\n <span>view</span><span>.</span><span>set<wbr>Content<wbr>Hugging<wbr>Priority</span><span>(</span><span>.</span><span>default<wbr>High</span><span>,</span> <span>for</span><span>:</span> <span>.</span><span>vertical</span><span>)</span>\n <span>}</span>\n <span>}</span>\n <span>#endif</span>\n </code></pre>\n</details>\n</aside>\n<h2>\n<a href=\"https://nshipster.com/swiftui-previews/#previewing-multiple-states\"></a>Previewing Multiple States</h2>\n<p>Let\u2019s say our app had a <code>Favorite<wbr>Button</code> \u2014\na distant cousin (perhaps by composition) to <code>Bordered<wbr>Button</code>.\nIn its default state,\nit shows has the title \u201cFavorite\u201d\nand displays a <span title=\"Heart\">\u2661</span> icon.\nWhen its <code>is<wbr>Favorited</code> property is set to <code>true</code>,\nthe title is set to \u201cUnfavorite\u201d\nand displays a <span title=\"Heart with slash\">\u2661\u0338</span> icon.</p>\n<p>We can preview both at once\nby wrapping two <code>UIView<wbr>Preview</code> instances within a single SwiftUI <code>Group</code>:</p>\n<div>\n<pre data-lang=\"Swift\"><code><span>Group</span> <span>{</span>\n <span>UIView<wbr>Preview</span> <span>{</span>\n <span>let</span> <span>button</span> <span>=</span> <span>Favorite<wbr>Button</span><span>(</span><span>frame</span><span>:</span> <span>.</span><span>zero</span><span>)</span>\n <span>return</span> <span>button</span>\n <span>}</span>\n <span>UIView<wbr>Preview</span> <span>{</span>\n <span>let</span> <span>button</span> <span>=</span> <span>Favorite<wbr>Button</span><span>(</span><span>frame</span><span>:</span> <span>.</span><span>zero</span><span>)</span>\n <span>button</span><span>.</span><span>is<wbr>Favorited</span> <span>=</span> <span>true</span>\n <span>return</span> <span>button</span>\n <span>}</span>\n <span>}</span><span>.</span><span>preview<wbr>Layout</span><span>(</span><span>.</span><span>size<wbr>That<wbr>Fits</span><span>)</span>\n <span>.</span><span>padding</span><span>(</span><span>10</span><span>)</span>\n </code></pre>\n<aside>\n<p><img alt=\"SwiftUI previews with Favorite and Unfavorite buttons\" src=\"https://nshipster.com/assets/swiftui-preview-favorite-unfavorite-e0658904f16daa64c98d7ae4e9e35d011f3c1996da29b3aecc4a8c438298e13f.png\"></p>\n</aside>\n</div>\n<aside>\n<p>The chained <code>preview<wbr>Layout</code> and <code>padding</code> methods\napply to each member of the <code>Group</code>.\nYou can use these and\n<a rel=\"noopener noreferrer\" href=\"https://developer.apple.com/documentation/swiftui/view\">other <code>View</code> methods</a>\nto change the appearance of your previews.</p>\n</aside>\n<h2>\n<a href=\"https://nshipster.com/swiftui-previews/#previewing-dark-mode\"></a>Previewing Dark Mode</h2>\n<p>With <a href=\"https://nshipster.com/dark-mode/\">Dark Mode in iOS 13</a>,\nit\u2019s always a good idea to double-check that your custom views\nare configured with dynamic colors\nor accommodate both light and dark appearance in some other way.</p>\n<p>An easy way to do this\nwould be to use a <code>For<wbr>Each</code> element\nto render a preview for each case in the <code>Color<wbr>Scheme</code> enumeration:</p>\n<div>\n<pre data-lang=\"Swift\"><code><span>For<wbr>Each</span><span>(</span><span>Color<wbr>Scheme</span><span>.</span><span>all<wbr>Cases</span><span>,</span> <span>id</span><span>:</span> <span>\\</span><span>.</span><span>self</span><span>)</span> <span>{</span> <span>color<wbr>Scheme</span> <span>in</span>\n <span>UIView<wbr>Preview</span> <span>{</span>\n <span>let</span> <span>button</span> <span>=</span> <span>Bordered<wbr>Button</span><span>(</span><span>frame</span><span>:</span> <span>.</span><span>zero</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Title</span><span>(</span><span>"Subscribe"</span><span>,</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Image</span><span>(</span><span>UIImage</span><span>(</span><span>system<wbr>Name</span><span>:</span> <span>"plus"</span><span>),</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Title<wbr>Color</span><span>(</span><span>.</span><span>system<wbr>Orange</span><span>,</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>tint<wbr>Color</span> <span>=</span> <span>.</span><span>system<wbr>Orange</span>\n <span>return</span> <span>button</span>\n <span>}</span><span>.</span><span>environment</span><span>(\\</span><span>.</span><span>color<wbr>Scheme</span><span>,</span> <span>color<wbr>Scheme</span><span>)</span>\n <span>.</span><span>preview<wbr>Display<wbr>Name</span><span>(</span><span>"</span><span>\\(</span><span>color<wbr>Scheme</span><span>)</span><span>"</span><span>)</span>\n <span>}</span><span>.</span><span>preview<wbr>Layout</span><span>(</span><span>.</span><span>size<wbr>That<wbr>Fits</span><span>)</span>\n <span>.</span><span>background</span><span>(</span><span>Color</span><span>(</span><span>.</span><span>system<wbr>Background</span><span>))</span>\n <span>.</span><span>padding</span><span>(</span><span>10</span><span>)</span>\n </code></pre>\n<aside>\n<p><img alt=\"SwiftUI previews with different color schemes\" src=\"https://nshipster.com/assets/swiftui-preview-color-schemes-34bd0a96b6e3768b29f0ddd537ee99243fed2430bc42a7a4f535fad5ec533fbe.png\"></p>\n</aside>\n</div>\n<aside>\n<p>When rendering previews with <code>For<wbr>Each</code>,\nuse the <code>preview<wbr>Display<wbr>Name</code> method to help distinguish among\nall of the enumerated values.</p>\n</aside>\n<h2>\n<a href=\"https://nshipster.com/swiftui-previews/#previewing-dynamic-type-size-categories\"></a>Previewing Dynamic Type Size Categories</h2>\n<p>We can use the same approach to preview our views in various\n<a rel=\"noopener noreferrer\" href=\"https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/typography/\">Dynamic Type Sizes</a>:</p>\n<div>\n<pre data-lang=\"Swift\"><code><span>For<wbr>Each</span><span>(</span><span>Content<wbr>Size<wbr>Category</span><span>.</span><span>all<wbr>Cases</span><span>,</span> <span>id</span><span>:</span> <span>\\</span><span>.</span><span>self</span><span>)</span> <span>{</span> <span>size<wbr>Category</span> <span>in</span>\n <span>UIView<wbr>Preview</span> <span>{</span>\n <span>let</span> <span>button</span> <span>=</span> <span>Bordered<wbr>Button</span><span>(</span><span>frame</span><span>:</span> <span>.</span><span>zero</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Title</span><span>(</span><span>"Subscribe"</span><span>,</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Image</span><span>(</span><span>UIImage</span><span>(</span><span>system<wbr>Name</span><span>:</span> <span>"plus"</span><span>),</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Title<wbr>Color</span><span>(</span><span>.</span><span>system<wbr>Orange</span><span>,</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>tint<wbr>Color</span> <span>=</span> <span>.</span><span>system<wbr>Orange</span>\n <span>return</span> <span>button</span>\n <span>}</span><span>.</span><span>environment</span><span>(\\</span><span>.</span><span>size<wbr>Category</span><span>,</span> <span>size<wbr>Category</span><span>)</span>\n <span>.</span><span>preview<wbr>Display<wbr>Name</span><span>(</span><span>"</span><span>\\(</span><span>size<wbr>Category</span><span>)</span><span>"</span><span>)</span>\n <span>}</span><span>.</span><span>preview<wbr>Layout</span><span>(</span><span>.</span><span>size<wbr>That<wbr>Fits</span><span>)</span>\n <span>.</span><span>padding</span><span>(</span><span>10</span><span>)</span>\n </code></pre>\n<aside>\n<p><img alt=\"SwiftUI previews with different content size categories\" src=\"https://nshipster.com/assets/swiftui-preview-content-size-categories-33be9504b46e4fbfc96f152a165378b9b517c1ca54c20ea21096a7767c49dd67.png\"></p>\n</aside>\n</div>\n<h2>\n<a href=\"https://nshipster.com/swiftui-previews/#previewing-different-locales\"></a>Previewing Different Locales</h2>\n<p>Xcode Previews are especially time-saving when it comes to\nlocalizing an app into multiple languages.\nCompared to the hassle of configuring Simulator\nback and forth between different languages and regions,\nthis new approach makes a world of difference.</p>\n<p>Let\u2019s say that, in addition to English,\nyour app supported various <a rel=\"noopener noreferrer\" href=\"https://en.wikipedia.org/wiki/Right-to-left\">right-to-left languages</a>.\nYou could verify that your\n<abbr title=\"Right-to-Left\">RTL</abbr> logic worked as expected like so:</p>\n<div>\n<pre data-lang=\"Swift\"><code><span>let</span> <span>supported<wbr>Locales</span><span>:</span> <span>[</span><span>Locale</span><span>]</span> <span>=</span> <span>[</span>\n <span>"en-US"</span><span>,</span> <span>// English (United States)</span>\n <span>"ar-QA"</span><span>,</span> <span>// Arabic (Qatar)</span>\n <span>"he-IL"</span><span>,</span> <span>// Hebrew (Israel)</span>\n <span>"ur-IN"</span> <span>// Urdu (India)</span>\n <span>]</span><span>.</span><span>map</span><span>(</span><span>Locale</span><span>.</span><span>init</span><span>(</span><span>identifier</span><span>:))</span>\n <span>func</span> <span>localized<wbr>String</span><span>(</span><span>_</span> <span>key</span><span>:</span> <span>String</span><span>,</span> <span>for</span> <span>locale</span><span>:</span> <span>Locale</span><span>)</span> <span>-></span> <span>String</span><span>?</span> <span>{</span> <var>...</var> <span>}</span>\n <span>return</span> <span>For<wbr>Each</span><span>(</span><span>supported<wbr>Locales</span><span>,</span> <span>id</span><span>:</span> <span>\\</span><span>.</span><span>identifier</span><span>)</span> <span>{</span> <span>locale</span> <span>in</span>\n <span>UIView<wbr>Preview</span> <span>{</span>\n <span>let</span> <span>button</span> <span>=</span> <span>Bordered<wbr>Button</span><span>(</span><span>frame</span><span>:</span> <span>.</span><span>zero</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Title</span><span>(</span><span>localized<wbr>String</span><span>(</span><span>"Subscribe"</span><span>,</span> <span>for</span><span>:</span> <span>locale</span><span>),</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Image</span><span>(</span><span>UIImage</span><span>(</span><span>system<wbr>Name</span><span>:</span> <span>"plus"</span><span>),</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>set<wbr>Title<wbr>Color</span><span>(</span><span>.</span><span>system<wbr>Orange</span><span>,</span> <span>for</span><span>:</span> <span>.</span><span>normal</span><span>)</span>\n <span>button</span><span>.</span><span>tint<wbr>Color</span> <span>=</span> <span>.</span><span>system<wbr>Orange</span>\n <span>return</span> <span>button</span>\n <span>}</span><span>.</span><span>environment</span><span>(\\</span><span>.</span><span>locale</span><span>,</span> <span>locale</span><span>)</span>\n <span>.</span><span>preview<wbr>Display<wbr>Name</span><span>(</span><span>Locale</span><span>.</span><span>current</span><span>.</span><span>localized<wbr>String</span><span>(</span><span>for<wbr>Identifier</span><span>:</span> <span>locale</span><span>.</span><span>identifier</span><span>))</span>\n <span>}</span><span>.</span><span>preview<wbr>Layout</span><span>(</span><span>.</span><span>size<wbr>That<wbr>Fits</span><span>)</span>\n <span>.</span><span>padding</span><span>(</span><span>10</span><span>)</span>\n </code></pre>\n<aside>\n<p><img alt=\"SwiftUI previews with different locales\" src=\"https://nshipster.com/assets/swiftui-preview-locales-4a05412203ff6074a58a86ad4e5e742e8250d2f70ae898c27c19fa5bd4a405f5.png\"></p>\n</aside>\n</div>\n<aside>\n<p>We don\u2019t know of an easy way to use <code>NSLocalized<wbr>String</code> with an explicit locale.\nYou could go to the trouble of retrieving localized strings\nfrom a strings file in your bundle,\nbut in most cases,\nyou\u2019ll be just fine hard-coding text in your previews.</p>\n</aside>\n<h2>\n<a href=\"https://nshipster.com/swiftui-previews/#previewing-view-controllers-on-different-devices\"></a>Previewing View Controllers on Different Devices</h2>\n<p>SwiftUI previews aren\u2019t limited to views,\nyou can also use them with view controllers.\nBy creating a <a rel=\"noopener noreferrer\" href=\"https://gist.github.com/mattt/ff6b58af8576c798485b449269d43607\">custom <code>UIView<wbr>Controller<wbr>Preview</code> type</a>\nand taking advantage of some\n<a href=\"https://nshipster.com/ios-13/#remove-implicitly-unwrapped-optionals-from-view-controllers-initialized-from-storyboards\">new <code>UIStoryboard</code> class methods in iOS 13</a>,\nwe can easily preview our view controller\non various devices \u2014\none on top of another:</p>\n<div>\n<pre data-lang=\"Swift\"><code><span>#if can<wbr>Import(Swift<wbr>UI) && DEBUG</span>\n <span>import</span> <span>Swift<wbr>UI</span>\n <span>let</span> <span>device<wbr>Names</span><span>:</span> <span>[</span><span>String</span><span>]</span> <span>=</span> <span>[</span>\n <span>"i<wbr>Phone SE"</span><span>,</span>\n <span>"i<wbr>Pad 11 Pro Max"</span><span>,</span>\n <span>"i<wbr>Pad Pro (11-inch)"</span>\n <span>]</span>\n <span>@available(i<wbr>OS 13.0, *)</span>\n <span>struct</span> <span>View<wbr>Controller_Preview</span><span>:</span> <span>Preview<wbr>Provider</span> <span>{</span>\n <span>static</span> <span>var</span> <span>previews</span><span>:</span> <span>some</span> <span>View</span> <span>{</span>\n <span>For<wbr>Each</span><span>(</span><span>device<wbr>Names</span><span>,</span> <span>id</span><span>:</span> <span>\\</span><span>.</span><span>self</span><span>)</span> <span>{</span> <span>device<wbr>Name</span> <span>in</span>\n <span>UIView<wbr>Controller<wbr>Preview</span> <span>{</span>\n <span>UIStoryboard</span><span>(</span><span>name</span><span>:</span> <span>"Main"</span><span>,</span> <span>bundle</span><span>:</span> <span>nil</span><span>)</span>\n <span>.</span><span>instantiate<wbr>Initial<wbr>View<wbr>Controller</span> <span>{</span> <span>coder</span> <span>in</span>\n <span>View<wbr>Controller</span><span>(</span><span>coder</span><span>:</span> <span>coder</span><span>)</span>\n <span>}</span><span>!</span>\n <span>}</span><span>.</span><span>preview<wbr>Device</span><span>(</span><span>Preview<wbr>Device</span><span>(</span><span>raw<wbr>Value</span><span>:</span> <span>device<wbr>Name</span><span>))</span>\n <span>.</span><span>preview<wbr>Display<wbr>Name</span><span>(</span><span>device<wbr>Name</span><span>)</span>\n <span>}</span>\n <span>}</span>\n <span>}</span>\n <span>#endif</span>\n </code></pre>\n<aside>\n<p><img alt=\"SwiftUI previews with different devices\" src=\"https://nshipster.com/assets/swiftui-preview-devices-c15a3ade082a4860c53f81fc6b5f3975e92d1570663c9e79cd10889d872564ad.png\"></p>\n</aside>\n</div>\n<aside>\n<p>There\u2019s currently no way to get SwiftUI device previews in landscape orientation.\nAlthough you can approximate this with a fixed size preview layout,\nbe aware that it won\u2019t respect Safe Area on iPhone\nor render split views correctly on iPad.</p>\n</aside>\n<hr>\n<p>Although most of us are still some years away from shipping SwiftUI in our apps\n(whether by choice or necessity),\nwe can all immediately benefit from the order-of-magnitude improvement\nit enables with Xcode 11 on macOS Catalina.</p>\n<p>By eliminating so much time spent waiting for things to happen,\nwe not only get (literally) <em>hours</em> more time each week,\nbut we unlock the possibility of maintaining an unbroken flow state during that time.\nNot only that,\nbut the convenience of integrated tests\nfundamentally changes the calculus for testing:\ninstead of being a rare <em>\u201cnice to have,\u201d</em>\nthey\u2019re the new default.\nPlus:\nthese inline previews serve as living documentation\nthat can help teams both large and small\nfinally get a handle on their design system.</p>\n<p>It\u2019s hard to overstate how much of a game-changer Xcode Previews are for iOS development,\nand we couldn\u2019t be happier to incorporate them into our workflow.</p>\n"
|
|
},
|
|
"visual": {
|
|
"url": "none"
|
|
},
|
|
"unread": false,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/885f2e01-d314-4e63-abac-17dcb063f5b5",
|
|
"label": "Programming"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
}
|
|
],
|
|
"actionTimestamp": 1571037592868
|
|
},
|
|
{
|
|
"originId": "tag:blogger.com,1999:blog-8954608646904080796.post-3215871338266756283",
|
|
"fingerprint": "717870dc",
|
|
"thumbnail": [
|
|
{
|
|
"url": "https://1.bp.blogspot.com/-JTONCNpv2X8/XaEUgnGZSzI/AAAAAAAADTg/EaM5cDjkD3kRnXPIR0-6AX-3VxlC_br_QCEwYBhgL/s72-c/091.jpg",
|
|
"width": 72,
|
|
"height": 72
|
|
}
|
|
],
|
|
"id": "v0v+7Ya8tssIZvd3/pcnFRr3HwvY/5YK3FGc2t65c0Y=_16dbd619e56:82fa:d4506071",
|
|
"updated": 1570837682218,
|
|
"author": "Edward Feser",
|
|
"alternate": [
|
|
{
|
|
"href": "http://edwardfeser.blogspot.com/2019/10/around-web.html",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1570840354390,
|
|
"title": "Around the web",
|
|
"published": 1570837680000,
|
|
"origin": {
|
|
"streamId": "feed/http://edwardfeser.blogspot.com/feeds/posts/default",
|
|
"htmlUrl": "http://edwardfeser.blogspot.com/",
|
|
"title": "Edward Feser"
|
|
},
|
|
"content": {
|
|
"direction": "ltr",
|
|
"content": "<br><div></div><div></div><div><a href=\"https://1.bp.blogspot.com/-JTONCNpv2X8/XaEUgnGZSzI/AAAAAAAADTg/EaM5cDjkD3kRnXPIR0-6AX-3VxlC_br_QCEwYBhgL/s1600/091.jpg\"><img border=\"0\" src=\"https://1.bp.blogspot.com/-JTONCNpv2X8/XaEUgnGZSzI/AAAAAAAADTg/EaM5cDjkD3kRnXPIR0-6AX-3VxlC_br_QCEwYBhgL/s200/091.jpg\" data-original-width=\"166\" width=\"136\" data-original-height=\"243\" height=\"200\"></a></div><div><span>At <i>The Catholic Thing</i>, Fr. Thomas Weinandy on <span><a href=\"https://www.thecatholicthing.org/2019/10/08/pope-francis-and-schism/\">the studied ambiguity of Pope Francis.</a></span>\u00a0 In his new book <i>Conciliar Octet</i>, Fr. Aidan Nichols on <a href=\"https://www.catholicworldreport.com/2019/08/22/fr-aidan-nichols-conciliar-octet-is-a-welcome-guide-to-the-eight-key-texts-of-vatican-ii/\">the hermeneutic of continuity and Vatican II</a>. </span></div><div><span><br></span></div><div><span>At <i>Medium</i>, philosopher Kathleen Stock on <span><a href=\"https://medium.com/@kathleenstock/are-academics-freely-able-to-criticise-the-idea-of-gender-identity-in-uk-universities-67b97c6e04be\">gender theory versus academic freedom in the UK</a></span>.<span>\u00a0 </span>At <i>Inside Higher Education</i>, twelve prominent philosophers <span><a href=\"https://www.insidehighered.com/views/2019/07/22/philosophers-should-not-be-sanctioned-their-positions-sex-and-gender-opinion\">defend the right to free inquiry on matters of sex and gender</a></span>.<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span>Philosopher Daniel A. Kaufman on <span><a href=\"https://theelectricagora.com/2019/09/08/philosophys-aspirant-tin-pot-dictators/\">the \u201cwoke\u201d fanatics increasingly infesting academic philosophy</a></span>, at <i>The Electric Agora</i>.<span>\u00a0 </span>Richard Marshall <span><a href=\"https://316am.site123.me/articles/anti-theory-philosophy?c=end-times-series\">interviews Kaufman</a></span> at <i>3:16</i>.<span>\u00a0</span></span></div><a name=\"more\"></a> <br> <div><span>Peggy Noonan on <u><a href=\"http://peggynoonan.com/what-were-robespierres-pronouns/\">transgender Jacobinism</a></u>, at <i>The Wall Street Journal</i>.<span>\u00a0 </span>At YouTube, <u><a href=\"https://www.youtube.com/watch?v=IzNGkwGYE4E\">video of an indoctrination session</a></u>.<span><span></span></span></span></div><div><span><br></span></div><div><span>Jacob Howland on <span><a href=\"https://newcriterion.com/issues/2019/10/borgess-mirror\">Borges\u2019s Library of Babel</a></span>, at <i>The New Criterion</i>.</span></div><div><span><br></span></div><div><span>At <i>New Statesman</i>, John Gray on Tom Holland on <u><a href=\"https://www.newstatesman.com/dominion-making-western-mind-tom-holland-review\">the Christian origins of modern secular liberal values</a></u>.<span>\u00a0 </span>More reviews <u><a href=\"https://kirkcenter.org/reviews/the-origin-of-the-secular-species/\">at <i>The University Bookman</i></a></u> and <u><a href=\"https://literaryreview.co.uk/it-began-in-a-manger\">at <i>Literary Review</i></a></u>.</span></div><div><span><br></span></div><div><span>At <i>Quillette</i>, Benedict Beckeld diagnoses <span><a href=\"https://quillette.com/2019/10/07/oikophobia-our-western-self-hatred/\">Western self-hatred or <i>oikophobia</i></a></span>.</span></div><div><span><br></span></div><div><u><span><a href=\"http://www.axs.tv/featured/shaffer-105/\">Donald Fagen interviewed</a></span></u><span> on <i>Paul Shaffer Plus One</i>.</span></div><div><span><br></span></div><div><span>Kay Hymowitz on <span><a href=\"https://www.washingtonexaminer.com/opinion/a-nation-dying-in-despair-and-family-breakdown-is-part-of-the-problem\">the sexual revolution and mental health</a></span>, at <i>The Washington Examiner</i>.</span></div><div><span><br></span></div><div><span>John DeRosa of the Classical Theism Podcast <span><a href=\"http://www.classicaltheism.com/kerr/\">interviews Thomist philosopher Gaven Kerr</a></span> on the topic of Aquinas and creation.</span></div><div><span><br></span></div><div><span>Ronald W. Dworkin on <span><a href=\"https://www.the-american-interest.com/2019/10/08/artificial-intelligence-whats-to-fear/\">\u201cartificial intelligence\u201d as a projection of artificial intelligence researchers</a></span>, at <i>The American Interest</i>.</span></div><div><span><br></span></div><div><span>New books on Aquinas: <span><i><a href=\"https://global.oup.com/academic/product/aquinas-and-the-metaphysics-of-creation-9780190941307?cc=us&lang=en&\">Aquinas and the Metaphysics of Creation</a></i></span>, by Gaven Kerr; <span><i><a href=\"https://www.hfsbooks.com/books/the-discovery-of-being-and-thomas-aquinas-cullen-harkins/\">The Discovery of Being and Thomas Aquinas</a></i></span>, edited by Christopher Cullen and Franklin Harkins; <span><i><a href=\"https://www.springer.com/gp/book/9783030339111#aboutAuthors\">The Human Person: What Aristotle and Thomas Aquinas Offer Modern Psychology</a></i></span>, by Thomas Spalding, James Stedman, Christina Gagn\u00e9, and Matthew Kostelecky</span><span>.<span></span></span></div><div><span><br></span></div><div><span>At the <i>Institute of Art and Ideas</i>: Philosopher of physics Tim Maudlin on <span><a href=\"https://iai.tv/articles/quantum-theory-and-common-sense-auid-1254\">quantum physics and common sense</a></span>.<span>\u00a0 </span>Physicist Subir Sarkar and philosophers Nancy Cartwright and John Dupr\u00e9 <span><a href=\"https://iai.tv/video/the-end-of-all-things-what-is-reality-made-of-metaphysics\">discuss physics and materialism</a></span>.</span></div><div><span><br></span></div><div><span>Philosopher Dennis Bonnette on <span><a href=\"https://strangenotions.com/why-humans-are-more-than-mere-animals/\">the distinction between the intellect and the imagination</a></span>, at <i>Strange Notions</i>.</span></div><div><span><br></span></div><div><span>Philosopher of time <span><a href=\"https://316am.site123.me/articles/moving-spotlight-metaphysics-and-other-stuff?c=end-times-series\">Ross Cameron is interviewed</a></span> by Richard Marshall at <i>3:16</i>.</span></div><div><span><br></span></div><div><span>Duns Scotus in focus at <i><u><a href=\"https://philosophynow.org/issues/127/Duns_Scotus_1265_66-1308?utm_term=Autofeed&utm_medium=Social&cpg=ebtw&utm_source=Twitter#Echobox=1562194883\">Philosophy Now</a></u></i> and <i><u><a href=\"https://www.commonwealmagazine.org/have-you-tried-scotus\">Commonweal</a></u></i>.<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><span><a href=\"http://mentalfloss.com/article/585008/alfred-hitchcock-presents-facts\">10 facts about\u00a0<i>Alfred Hitchcock Presents</i></a><span>, at <i>Mental Floss</i>.</span></span></div><div><br></div><div><span>Tim Maudlin on <span><a href=\"https://bostonreview.net/science-nature/tim-maudlin-why-world?fbclid=IwAR3m9AO4OVK9FkgSZ5sI8YQTw8ADc4QQ2UCn0Sm5PclvxqvjhJjnjMy_NPc\">Judea Pearl on causation versus correlation</a></span>, at the <i>Boston Review</i>.<span>\u00a0 </span>Maudlin\u2019s book <i><span>Philosophy of Physics: Quantum Theory</span></i><span> <span><a href=\"https://ndpr.nd.edu/news/philosophy-of-physics-quantum-theory/\">is reviewed</a></span> at <i>Notre Dame Philosophical Reviews</i>.</span></span></div><div><span><span><br></span></span></div><div><span>Charles Styles interviews Peter Harrison on the subject of <span><a href=\"https://fivebooks.com/best-books/history-science-and-religion-peter-harrison/\">the best books on the history of science and religion</a></span>, at <i>Five Books</i>.</span></div><div><span><br></span></div><div><span>At <i>Quillette</i>, Kevin Mims on <span><i><a href=\"https://quillette.com/2019/09/13/william-peter-blattys-counter-countercultural-parable/\">The Exorcist<span> as a film about the breakdown of the family</span></a></i></span>.</span></div><div><span><br></span></div><div><i><span>Society in Mind</span></i><span> on <span><a href=\"https://societyinmind.com/2019/08/13/beneath-the-replication-crisis/\">the replication crisis in psychology</a></span>.</span></div><div><span><br></span></div><div><span>Matias Slavov on <span><a href=\"https://aeon.co/essays/what-albert-einstein-owes-to-david-humes-notion-of-time\">Hume and Einstein on the nature of time</a></span>, at <i>Aeon</i>.</span></div><div><span><br></span></div><div><span>At <i>Catholic World Report</i>, philosopher Joseph Trabbic on <span><a href=\"https://www.catholicworldreport.com/2019/09/18/thomism-and-political-liberalism-part-2/\">Aquinas and political liberalism</a></span>.<span><span></span></span></span></div><div><span><br></span></div><div><i><span>Boston Review</span></i><span> on <span><a href=\"https://bostonreview.net/philosophy-religion/katrina-forrester-future-political-philosophy\">post-liberal academic political philosophy</a></span>.<span>\u00a0 </span><i>The Chronicle of Higher Education</i>on <span><a href=\"https://www.chronicle.com/interactives/20190912-academias-holy-warriors?key=mi0Bff1vaLHL09_no2EmgyubkYGaE_Z0wYeVvMXRpBMlzD16oZl7OvOuo9-6VB1CQ1pUYTE5WnhOR1J5VUFMaG1lRk1TdExEQ1VIbkRnQXRiYkZkdzh4VER0MA\">post-liberal Catholic political philosophy</a></span>.<span>\u00a0 </span></span></div><div><span><span><br></span></span></div><div><i><span><a href=\"https://www.amazon.com/Blue-World-John-Coltrane/dp/B07VQTJ24X/ref=tmm_acd_swatch_0?_encoding=UTF8&qid=1570834820&sr=8-1\">Blue World</a></span></i><span>, an album of lost John Coltrane tracks, <a href=\"https://www.theguardian.com/music/2019/sep/27/john-coltrane-blue-world-review\">has been released</a>.</span></div><div><span><br></span></div><div><span>It\u2019s a thing.<span>\u00a0 </span><i>The Huffington Post</i> reports on <span><a href=\"https://www.huffpost.com/highline/article/millennial-nuns/?guce_referrer=aHR0cHM6Ly90LmNvL1JIdXVhTjlTMHU&guce_referrer_sig=AQAAAKxj_Bm_NFaQWyWT2RPd2P6rfBbWMgCJPbUxhqTn7Fdecu8HgfzTlbd86V4ExNaoyeVmJOyDI00RQGJkVgc3GmO0deVEaGXPwwHtHUmfgTD2i8_0zUWCCCvEL0XqanrNIoGWugj9sspmIZVEGtAT_e94HA6TxKExBNVohlcRDj_F&guccounter=2\">millennials who are becoming nuns</a></span>.</span></div><div><span><br></span></div><div><span>Scott Alexander on LGBT as a new civil religion, at <span><i><a href=\"https://slatestarcodex.com/2019/07/08/gay-rites-are-civil-rites/\">Slate Star Codex</a></i></span>.\u00a0 C. C. Pecknold on <span><a href=\"https://catholicherald.co.uk/commentandblogs/2019/07/02/the-pride-flag-flies-everywhere-but-what-does-it-stand-for/\">the phony neutrality of post-Obergefell liberalism</a></span>, at <i>Catholic Herald</i>.</span></div>"
|
|
},
|
|
"visual": {
|
|
"url": "http://b.vimeocdn.com/ts/452/218/452218069_1280.jpg",
|
|
"width": 1280,
|
|
"height": 720,
|
|
"contentType": "image/jpeg"
|
|
},
|
|
"unread": false,
|
|
"categories": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/5ca4d61d-e55d-4999-a8d1-c3b9d8789815",
|
|
"label": "Macintosh"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/fbdcd69b-7e27-4b6a-bfed-6584b944155d",
|
|
"label": "\ud83e\udd1e\ud83c\udffb\ud83e\udd1e\ud83c\udffb\ud83e\udd1e\ud83c\udffb"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
}
|
|
],
|
|
"actionTimestamp": 1571037184309
|
|
},
|
|
{
|
|
"keywords": [
|
|
"Google",
|
|
"Apple Arcade"
|
|
],
|
|
"originId": "https://www.macrumors.com/2019/09/26/apple-arcade-vs-google-play-pass/",
|
|
"fingerprint": "fd93a55d",
|
|
"id": "SusR11hdg5ydv7o+xGl+0XlI0AhBL77Oxid8QOO3j5k=_16d6f7df794:48e16:18991ffa",
|
|
"author": "Juli Clover",
|
|
"summary": {
|
|
"direction": "ltr",
|
|
"content": "With the launch of <a href=\"https://www.macrumors.com/roundup/ios-13/\">iOS 13</a>, <a href=\"https://www.macrumors.com/2019/09/19/apple-arcade-live-ios-13/\">Apple released Apple Arcade</a>, a new $4.99 per month gaming service that provides unlimited access to new and exclusive games.\n<br>\n<br>\nLess than two weeks later, Google <a href=\"https://www.macrumors.com/2019/09/23/google-launches-new-play-pass-service-on-android/\">announced its own gaming service</a> called Play Pass, which also offers unlimited access to games. In our latest YouTube video, we went hands-on with both services to compare them.\n<br>\n<br>\n<center><iframe allowfullscreen src=\"https://www.youtube.com/embed/klZfwC5Wh9I\" width=\"560\" height=\"315\"></iframe></center><center><em><a href=\"https://www.youtube.com/user/macrumors?sub_confirmation=1\">Subscribe to the MacRumors YouTube channel</a> for more videos.</em></center>\n<br>\nBoth <a href=\"https://www.apple.com/apple-arcade/\">Apple Arcade</a> and <a href=\"https://play.google.com/about/play-pass/\">Play Pass</a> are priced at $4.99 per month. Apple offers a one-month free trial while Google offers a 10-day free trial, but for the first year, Google is offering a deal that drops the price of Play Pass to $1.99 per month.\n<br>\n<br>\nThough the prices are similar, the two services are quite different. <a href=\"https://www.macrumors.com/guide/apple-arcade/\">Apple Arcade</a> features new and exclusive games, some of which were funded by Apple, while Google's Play Pass offers up older games.\n<br>\n<br>\nPlay Pass includes some super popular titles like Stardew Valley, Reigns, Star Wars Knights of the Old Republic, Terraria, and more, but the problem with older games is that many people may have already played them.\n<br>\n<br>\nPlay Pass is also not limited to games -- Google is including apps too. AccuWeather, Pic Stitch, ISS HD, and Tunable are some of the apps offered.\n<br>\n<br>\nApple Arcade only offers gaming titles, but all of the games are fresh, new, and exclusive to Apple Arcade. In some cases, though, some of the games are also available on consoles, but on mobile platforms, Apple Arcade gets exclusive access. That means no Android equivalent.\n<br>\n<br>\nIt's not clear if apps can leave Apple Arcade, but Google warns that apps can leave Play Pass. If that happens, users will need to buy the game to continue to use it if it's a paid game, and for free titles, ads and in-app purchases may show up.\n<br>\n<br>\nGoogle says there are hundreds of apps and games included with more being added every month. Apple Arcade launched with right around 60 games, and Apple has also promised new content on a monthly basis. Both services offer offline gaming, so no internet connection is required.\n<br>\n<br>\nWith both services, content is ad free and features no in-app purchases. Apple titles were designed from the ground up with no additional purchases, but for Play Pass, these gaming elements have been removed from titles that previously offered them.\n<br>\n<br>\nApple allows up to six family members to share games through a single Apple Arcade subscription using Family Sharing, and Google allows for up to five family members to share content through its Google Play Family Library.\n<br>\n<br>\nApple Arcade has launched in multiple countries around the world, while Play Pass is limited to the United States at the current time. Google does plan to expand, however.\n<br>\n<br>\nOne other aspect worth noting is privacy. Apple specifically mentions privacy protections and says that users are able to choose to share data, while Google's Play Pass materials don't mention privacy or data sharing. "Every game must meet Apple's high privacy standards," reads Apple's <a href=\"https://www.apple.com/newsroom/2019/09/apple-arcade-invites-you-to-play-something-extraordinary/\">press release</a> for Apple Arcade.\n<br>\n<br>\nMost people are locked in to either Android or iOS and few have both, so most people won't need to choose between services.\n<br>\n<br>\nApple users who have a Mac, iPhone, <a href=\"https://www.macrumors.com/roundup/ipad/\">iPad</a>, or <a href=\"https://www.macrumors.com/roundup/apple-tv/\">Apple TV</a> can access Apple Arcade on those devices, while Google Play Pass requires a smartphone, laptop, or tablet with Android 4.4 or above and Play Store version 16.6.25. Google Play Pass games can't be played on the larger screen of a television, which gives Apple Arcade a bit of an edge when it comes to non-mobile gaming.\n<br>\n<br>\nDo you prefer Apple Arcade with its fresh selection of titles, or Google Play Pass with its larger library of already available games? Let us know in the comments.<br><br><div>Tags: <a href=\"https://www.macrumors.com/roundup/google/\">Google</a>, <a href=\"https://www.macrumors.com/roundup/apple-arcade/\">Apple Arcade</a></div><br>This article, "<a href=\"https://www.macrumors.com/2019/09/26/apple-arcade-vs-google-play-pass/\">Apple Arcade vs. Google Play Pass</a>" first appeared on <a href=\"https://www.macrumors.com\">MacRumors.com</a><br><br><a href=\"https://forums.macrumors.com/threads/apple-arcade-vs-google-play-pass.2201924/\">Discuss this article</a> in our forums<br><br><div>\n<a href=\"http://feeds.macrumors.com/~ff/MacRumors-Front?a=8qvKbZNFw68:13u-CPoeJ6s:yIl2AUoC8zA\"><img border=\"0\" src=\"http://feeds.feedburner.com/~ff/MacRumors-Front?d=yIl2AUoC8zA\"></a> <a href=\"http://feeds.macrumors.com/~ff/MacRumors-Front?a=8qvKbZNFw68:13u-CPoeJ6s:6W8y8wAjSf4\"><img border=\"0\" src=\"http://feeds.feedburner.com/~ff/MacRumors-Front?d=6W8y8wAjSf4\"></a> <a href=\"http://feeds.macrumors.com/~ff/MacRumors-Front?a=8qvKbZNFw68:13u-CPoeJ6s:qj6IDK7rITs\"><img border=\"0\" src=\"http://feeds.feedburner.com/~ff/MacRumors-Front?d=qj6IDK7rITs\"></a>\n</div><img width=\"1\" alt=\"\" src=\"http://feeds.feedburner.com/~r/MacRumors-Front/~4/8qvKbZNFw68\" height=\"1\">"
|
|
},
|
|
"alternate": [
|
|
{
|
|
"href": "https://www.macrumors.com/2019/09/26/apple-arcade-vs-google-play-pass/",
|
|
"type": "text/html"
|
|
}
|
|
],
|
|
"crawled": 1569533589396,
|
|
"title": "Apple Arcade vs. Google Play Pass",
|
|
"published": 1569531802000,
|
|
"origin": {
|
|
"streamId": "feed/http://www.macrumors.com/macrumors.xml",
|
|
"htmlUrl": "https://www.macrumors.com",
|
|
"title": "MacRumors: Mac News and Rumors - Front Page"
|
|
},
|
|
"visual": {
|
|
"url": "https://cdn.vox-cdn.com/thumbor/m3ztxUEeETYXD9gGfyEjUpS0GFE=/0x0:800x533/1310x873/cdn.vox-cdn.com/uploads/chorus_image/image/59662701/800x_1.0.jpg",
|
|
"width": 1310,
|
|
"height": 873,
|
|
"contentType": "image/jpeg"
|
|
},
|
|
"unread": false,
|
|
"readTime": 33744,
|
|
"tags": [
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.read",
|
|
"label": ""
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.unsaved",
|
|
"label": "Unsaved"
|
|
},
|
|
{
|
|
"id": "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/tag/global.saved",
|
|
"label": "Saved For Later"
|
|
}
|
|
],
|
|
"actionTimestamp": 1569536278861
|
|
}
|
|
]
|
|
}
|