tag:blogger.com,1999:blog-36068876669755365182024-03-09T18:46:20.925-08:00Mark WilkinsoniOS, Xamarin and Android Mobile App Developer in Houston, TX.Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-3606887666975536518.post-79606761873566824032017-11-01T22:28:00.000-07:002017-11-01T22:30:45.153-07:00Mvvm on Mobile?Here's my talk from Houston Tech Fest 2017.<br />
<br />
Recorded Talk:<br />
<br />
<!-- Please provide a link back to us and give the speaker credit! http://usergroup.tv/videos/mvvm-for-mobile-dont-do-it-cause-comeone-told-you -->
<iframe src="//player.vimeo.com/video/239089043" width="567" height="318" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
<br />
<br />
Slides:<br />
<a href="https://speakerdeck.com/markawil/mvvm-and-mobile-dont-do-it-cause-someone-told-you" target="_blank">https://speakerdeck.com/markawil/mvvm-and-mobile-dont-do-it-cause-someone-told-you</a><br />
<br />
Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com11tag:blogger.com,1999:blog-3606887666975536518.post-69223629502980484592017-10-21T15:02:00.001-07:002017-10-21T15:04:25.294-07:00iPhone Simulator Zombies, how to destroy themIf you're on the same machine for years, and multiple versions of OSX and Xcode, likely you'll build up a large list of simulators that show when you want to select a simulator to run your app on.<br />
<br />
As of Xcode 9 this became a breaking feature (at least for me). Xcode had a hard time scrolling through the massive list, so searching online found a few solutions, and I just compiled them together here:<br />
<br />
1) Remove yourself from iOS teams you no longer work on.<br />
<br />
As far as I can tell this is a recent addition, as before you had to ask the team admin to remove you.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlHvw9BAVsl5-9tnufc9PEWUskCGbDRVr_P3-6701dTfSZfCD8yVbd_5ASbMOYQQVHy_28-PQhBGaffXESyXV4F_g1Ej5zUQzEv8gcDe3-qtmOtoyYZ4nqMl8w-W6_uupX-JOLfmFOMVgD/s1600/Screen+Shot+2017-10-21+at+4.51.25+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="262" data-original-width="1544" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlHvw9BAVsl5-9tnufc9PEWUskCGbDRVr_P3-6701dTfSZfCD8yVbd_5ASbMOYQQVHy_28-PQhBGaffXESyXV4F_g1Ej5zUQzEv8gcDe3-qtmOtoyYZ4nqMl8w-W6_uupX-JOLfmFOMVgD/s640/Screen+Shot+2017-10-21+at+4.51.25+PM.png" width="640" /></a></div>
<br />
2) Remove the profiles from your machine (might as well nuke them all).<br />
<br />
The path to do this is here (credit goes to Alex from the Houston iPhone Developer UG):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOegrjNdTLdA1A9jWjM_Ny8xmjfO4vGrYUXrg7TNns9ui_Xsib0Xg7G5oUt-lU7oM4WJpBwpJ1MTSVQCAUksm-U4RCTBI3Eo2M4fK_MSF66AgaQZSdrCNxxXD06TMa27AW3xlz2HAxMHPS/s1600/Screen+Shot+2017-10-21+at+4.54.13+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="214" data-original-width="916" height="148" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOegrjNdTLdA1A9jWjM_Ny8xmjfO4vGrYUXrg7TNns9ui_Xsib0Xg7G5oUt-lU7oM4WJpBwpJ1MTSVQCAUksm-U4RCTBI3Eo2M4fK_MSF66AgaQZSdrCNxxXD06TMa27AW3xlz2HAxMHPS/s640/Screen+Shot+2017-10-21+at+4.54.13+PM.png" width="640" /></a></div>
<br />
3) Remove all the simulators you no longer need, I'd say remove all of them then reinstall the ones you want.<br />
<br />
In Xcode go Window -> Devices and Simulators<br />
<br />
Unfortunately there's no "Delete All" or select all feature. You'll have to manually delete them 1 at a time.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEmiSQVGIb3GwjxAOQQFF9bLY71hOTqc_W10yisjcbAtvDm8PCUs6F3SREMOqzcP8oK5aktG2WAwajAFL23YR-r58frQaG3Mei_R_PVqJkibD3DnpaTr18Fa-9Lf5uWY6bslzfpjEGD1c-/s1600/Screen+Shot+2017-10-19+at+1.58.17+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="756" data-original-width="1041" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEmiSQVGIb3GwjxAOQQFF9bLY71hOTqc_W10yisjcbAtvDm8PCUs6F3SREMOqzcP8oK5aktG2WAwajAFL23YR-r58frQaG3Mei_R_PVqJkibD3DnpaTr18Fa-9Lf5uWY6bslzfpjEGD1c-/s400/Screen+Shot+2017-10-19+at+1.58.17+PM.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Or if you're extremely brave (I'm not) you can try this in the command line:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Credit goes to Joao from the Houston iPhone Developers UG:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8gD5sddtErrNTxo80UyuZO61d1Hsf0-51wAOatkoo9wKRKtAY6PZInvW4wC1rYgRa5rX5hlZnRge1If2c_vpJ9sfShVGQU44n3P4w6nE-XqiMgkhwwg5qs2hAo89IlUF40bBwJkcdXDU1/s1600/Screen+Shot+2017-10-21+at+4.58.44+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="170" data-original-width="560" height="121" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8gD5sddtErrNTxo80UyuZO61d1Hsf0-51wAOatkoo9wKRKtAY6PZInvW4wC1rYgRa5rX5hlZnRge1If2c_vpJ9sfShVGQU44n3P4w6nE-XqiMgkhwwg5qs2hAo89IlUF40bBwJkcdXDU1/s400/Screen+Shot+2017-10-21+at+4.58.44+PM.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
I totally do not know if this will work, you've been warned :)</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
4) Add back the simulators along with their versions of iOS you want.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In the same Devices and Simulators page in Xcode at the bottom there is an add button:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOyBRHJFSE1jnnyMqOK2-6CVgwlAOcU_-jqIupQdzMNt4iI4KQ9fgJUG3TiJeovE5xXigdr8MzkBVGZf2V1f3OsmIi7sad1rbMovX9vBe_ymyeh-dMU2HPwW5ALajfnxZj4vzQcZSrI9Dy/s1600/Screen+Shot+2017-10-21+at+5.00.03+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="331" data-original-width="577" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOyBRHJFSE1jnnyMqOK2-6CVgwlAOcU_-jqIupQdzMNt4iI4KQ9fgJUG3TiJeovE5xXigdr8MzkBVGZf2V1f3OsmIi7sad1rbMovX9vBe_ymyeh-dMU2HPwW5ALajfnxZj4vzQcZSrI9Dy/s320/Screen+Shot+2017-10-21+at+5.00.03+PM.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now you should have a nice clean list of the simulators and the iOS versions to choose from:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
(before it was about 10-20 simulators of the same type with just a certificate number next to it)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfMoxgWlefdxwH9vGx4xcSbgQ3T5AInDPzm6f5OhVZmi7IMMorf6g8Dw56r8XiT8JcgwVg0ah5LReEhXcsdXkkHvTuHOzcLbFs55FhXxOsAzil6f9gma7rtwjrEA3t9l3IeIYjPF3DSvrt/s1600/Screen+Shot+2017-10-21+at+5.01.48+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="576" data-original-width="423" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfMoxgWlefdxwH9vGx4xcSbgQ3T5AInDPzm6f5OhVZmi7IMMorf6g8Dw56r8XiT8JcgwVg0ah5LReEhXcsdXkkHvTuHOzcLbFs55FhXxOsAzil6f9gma7rtwjrEA3t9l3IeIYjPF3DSvrt/s400/Screen+Shot+2017-10-21+at+5.01.48+PM.png" width="293" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
<br />Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com26tag:blogger.com,1999:blog-3606887666975536518.post-34089498221600579552016-06-20T19:43:00.000-07:002016-06-20T19:50:46.179-07:00awakeFromNib, layoutSubviews, dequeueReusableCellWithIdentifier and what happens in what order<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>If you have customized code in your UITableViewCell subclass like myself, you usually have some</title>
</head>
<body>
<p>If you have customized code in your UITableViewCell subclass like myself, you usually have some startup code for the cell, usually setting some constraints, or colors of text, default placeholder, etc. It generally doesn't matter whether this code goes in awakeFromNib or layoutSubviews, as long as what you do after dequeueReusableCellWithIdentifier doesn't depend on logic in either of these startup methods.</p>
<p>In the case where it does, you need to know which one happens in which order, in my case I'm using a custom UITextView that has placeholder text, via a nice blog post on how to do that:</p>
<p><a href="http://">https://grokswift.com/uitextview-placeholder/</a></p>
<p>The issue was that when opening a form to fill out for a new document the text is empty, so you need placeholder text. On top of this I have a label that needs to show (alpha = 1) when text from the user is inputted. When no text exists in the TextView the label needs to animate away and the Placeholder text needs to appear.</p>
<p>So you can see the possible logic branches I have, the issue was that at first launch of the cell before any text is set (if text already exists), my custom placeholder UITextView needs to get setup with constraints, placeholder text, placeholder text color, etc. But when the text already exists it needs to be set after the deque method is called, which then should disable the label and put the real text in the TextView (thus disabling the placeholder).</p>
<p>I got in a bind because I couldn't figure out which of these 3 methods run in which order, in this case, print out to console obviously shows you.</p>
<p>Here's the 3 important parts of code:</p>
<p>(called from the UITableViewController)</p>
<pre><code>let cell = tableView.dequeueReusableCellWithIdentifier(notesTextViewCellId)
</code></pre>
<p>(inside the UITableViewCell subclass)</p>
<pre><code>override func layoutSubviews() {
super.layoutSubviews()
print("layoutSubviews called")
// do startup code here?
}
override func awakeFromNib() {
super.awakeFromNib()
print("awakeFromNib called")
// or here?
}
</code></pre>
<p>or both?</p>
<p>In my case it was both.</p>
<p>Constraints needed to be in the awakeFromNib() and setting the placeholder logic needed to be in the layoutSubviews() as that happens AFTER the cell is dequed, where the awakeFromNib() happens before.</p>
<p>Here's the order when printed out to the console:</p>
<pre><code>awakeFromNib called
notesCell dequeued
layoutSubviews called
</code></pre>
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com3tag:blogger.com,1999:blog-3606887666975536518.post-42805653321107392082016-03-01T12:39:00.000-08:002016-03-01T12:39:10.747-08:00Draw a red border around your UIView for debugging purposes<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>A lot of the times, you're dealing with UITextViews and UITextFields that have the same</title>
</head>
<body>
<p>A lot of the times, you're dealing with UITextViews and UITextFields that have the same white background and border as the superviews they sit on top of. It's helpful every now and then to make sure they're obeying the constraints you want them to have. In my case, I made a self-contained UITextView that has a placeholder functionality but the textView wasn't constraining to the size of its container view.</p>
<p>DOH!</p>
<p><img src="http://i.imgur.com/i32o5vfl.png" alt="image" /></p>
<p>Ahh... needed better constraints:</p>
<pre><code>func applyConstraintsToTextView() {
if let validTextView = self.placeholderTextView {
let viewsDictionary = ["textView":validTextView]
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[textView]|", options: [], metrics: nil, views: viewsDictionary))
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[textView]|", options: [], metrics: nil, views: viewsDictionary))
setNeedsLayout()
}
}
</code></pre>
<p>Now add this extension to UIView</p>
<pre><code>extension UIView {
func drawRedBorder() {
self.layer.borderColor = UIColor.redColor().CGColor
self.layer.borderWidth = 1.0;
}
}
</code></pre>
<p>simply call it on the view (any UIView subclass) and see where the borders are landing.</p>
<pre><code>validTextView.drawRedBorder()
</code></pre>
<p>Much better...</p>
<p><img src="http://i.imgur.com/Jy0hwAY.png" alt="image" /></p>
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com2tag:blogger.com,1999:blog-3606887666975536518.post-67038744980697110512016-02-15T19:23:00.000-08:002016-02-15T19:23:19.211-08:00Quickly add a simple UIActivityIndicator to your screen<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>Sometimes you need to quickly throw a progress indicator over your view while something processes</title>
</head>
<body>
<p>Sometimes you need to quickly throw a progress indicator over your view while something processes (hopefully in the background).</p>
<p>I've found this code to be useful for that situation. Apply to your needs.</p>
<pre><code>UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithFrame:self.view.frame];
activityIndicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
activityIndicatorView.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5];
[self.view addSubview:activityIndicatorView];
[activityIndicatorView startAnimating];
[self.presentingViewController dismissViewControllerAnimated:YES completion:^{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
// do your processing in the background here
dispatch_sync(dispatch_get_main_queue(), ^{
// Update UI
[activityIndicatorView stopAnimating];
[activityIndicatorView removeFromSuperview];
});
});
}];
</code></pre>
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com1tag:blogger.com,1999:blog-3606887666975536518.post-30855156672368495952016-01-17T11:03:00.000-08:002016-01-17T11:06:44.793-08:00Finder shortcut to open a directory pathI find myself using this a lot after a co-worker showed me.
Basically, if you come across a directory path you need to get to, like to drop files into a folder or delete file, whatever, instead of manually clicking each directory to get to the destination, you can copy and paste the path into finder via<br />
<br />
<h2>
<b> ⌘ + Shift + G
</b></h2>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRMevM_8qPHPZdQgRnEOW5EQWAab0t5hLU1lsvqxMsBVPgTip3ouWFmLVTKrJhW781s98DgnAdQOMgyZJKeRmRpRicc7OCUdZN7rnowUFSqI7aN1YUeO4PpFq_zXlKEqxgFd9Dp0auTis5/s1600/Screen+Shot+2016-01-17+at+1.02.36+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRMevM_8qPHPZdQgRnEOW5EQWAab0t5hLU1lsvqxMsBVPgTip3ouWFmLVTKrJhW781s98DgnAdQOMgyZJKeRmRpRicc7OCUdZN7rnowUFSqI7aN1YUeO4PpFq_zXlKEqxgFd9Dp0auTis5/s320/Screen+Shot+2016-01-17+at+1.02.36+PM.png" width="320" /></a></div>
<br />Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com1tag:blogger.com,1999:blog-3606887666975536518.post-66786818155335227772016-01-06T11:10:00.003-08:002016-06-06T16:07:15.933-07:00Modularize your UIImagePickerController usage in Swift<html>
<head>
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Menlo;
}
code {
class: c-sharp;
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
class: c-sharp;
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>When you run across quick tutorials or answers on using UIImagePickerController the majority have you</title>
</head>
<body>
When you run across quick tutorials or answers on using UIImagePickerController the majority have you simply instantiating, containing, delegating and using it inside your UIViewController. As with most coding examples this is for demonstration purposes only, you should always, always abstract out functionality into reusable pieces in any application. The most obvious reason is that if one view controller needs the image picking functionalities, it's a safe bet that another will at some point. If not, well you'll probably run across another need for it in another application, much easier to strip out the code if it's self-containined in one class.<br />
The history of this code has been in Objective-C and it's served me well in more than one app, here I'm converting and using it in Swift for the first time in an app I'm currently building.<br />
To start, create a class, I like using Controller at the end of most classes or structs of this nature.<br />
<pre><code>class PhotoPickerController : NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate { }
</code></pre>
You do need to inherit from NSObject, if you don't the compiler will tell you that you either need to mark the delegate methods for UIImagePickerControllerDelegate with the prefix @objc or inherit from NSObject.<br />
Now setup your instance variables/properties (now the same thing in Swift remember)<br />
<pre><code>var alertController: UIAlertController?
weak var buttonToPresentPopoverForiPad: UIButton?
weak var viewController: UIViewController?
lazy var pickerController = UIImagePickerController()
</code></pre>
1) You'll need a UIAlertController (ActionSheet) to ask the user if they want to take a picture or load from the device/cameraroll.<br />
2) You need to have a weak reference to the button that will start the photo picker workflow so that if an iPad is used, the popOver functionality will work properly, remember on iPhone it's a modal popup, on iPad it's a pop-over.<br />
3) You need a weak reference to the UIViewController that will be presenting the workflow.<br />
4) Finally you need the core of all of this, an instance of UIImagePickerController, and because of swift lazy instantiation awesomeness, you can do it in one simple line. Create it when you first call it.<br />
Now comes the init for your custom container class. This will be the largest method and I suggest breaking it into smaller pieces, but for the sake of clarity,<br />
<pre class="js" name="code">init(buttonToPresentPopoverForiPad button: UIButton, viewControllerToPresent viewController: UIViewController) {
super.init()
self.alertController = UIAlertController(title: "Select a Photo", message: nil, preferredStyle: .ActionSheet)
self.buttonToPresentPopoverForiPad = button
self.viewController = viewController
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
self.alertController?.dismissViewControllerAnimated(false, completion: nil)
}
alertController?.addAction(cancelAction)
let photoAlbumAction = UIAlertAction(title: "Photo Album", style: .Default) { (action) in
self.selectPicture(.PhotoLibrary)
}
alertController?.addAction(photoAlbumAction)
let cameraAction = UIAlertAction(title: "Take a photo", style: .Default) { (action) -> Void in
self.selectPicture(.Camera)
}
alertController?.addAction(cameraAction)
alertController?.modalPresentationStyle = .Popover
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
let popOverPresenter = alertController?.popoverPresentationController
popOverPresenter?.sourceView = self.buttonToPresentPopoverForiPad
popOverPresenter?.sourceRect = self.viewController?.view.bounds as CGRect!
popOverPresenter?.permittedArrowDirections = .Any
}
}
</pre>
First, init the super which is NSObject like always, next setup your AlertController to be an ActionSheet with the proper actions, cancel, photo album and take a photo. Again the benefit of the newer UIAlertController API is that you can set the action results for each action inline with blocks, no more delegating to other methods.<br />
For Cancel, just dismiss the alert all together, nothing to see here, just move on.<br />
For Photo Album and Take a picture, you create a method that will open the appropriate modal workflow for each selection.<br />
Finally finish up your AlertController for dealing with the iPad.<br />
Now, here is the selectPicture helper method:<br />
<pre><code>private func selectPicture(pickerType: UIImagePickerControllerSourceType) {
if UIImagePickerController.isSourceTypeAvailable(pickerType){
pickerController.delegate = self
pickerController.sourceType = pickerType;
pickerController.mediaTypes = [kUTTypeImage as String]
pickerController.allowsEditing = false
pickerController.navigationBar.tintColor = UIColor.whiteColor()
self.viewController?.presentViewController(pickerController, animated: true, completion: nil)
}
}
</code></pre>
I generally now make my methods private that I obviously don't want available in the classes API. That's just my personal preference.<br />
Follow the standard practices now for setting up the UIImagePickerController outlined in Apple's documentation. Choose what will suit you for colors of the navbar, the mediatTypes, etc.<br />
Notice we set the delegate of the UIImagePickerControllerDelegate to self, this container class will handle the callbacks for the UIImagePickerController, instead of the more common example of a UIViewController bloated and dirty with all sorts of tasks assigned to it.<br />
Here's then how you handle those callbacks:<br />
Make sure you use the proper MARK: so indicating the delegate methods<br />
<pre><code>// MARK: - UIImagePickerControllerDelegate methods
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
self.pickerController.dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let mediaType = info[UIImagePickerControllerMediaType] as! NSString;
var originalImage, editedImage, imageToUse: UIImage?
if (CFStringCompare(mediaType as CFStringRef, kUTTypeImage, .CompareCaseInsensitive) == CFComparisonResult.CompareEqualTo) {
editedImage = info[UIImagePickerControllerEditedImage] as? UIImage
originalImage = info[UIImagePickerControllerOriginalImage] as? UIImage
if editedImage != nil {
imageToUse = editedImage
} else {
imageToUse = originalImage
}
if let validDelegate = delegate, let validImage = imageToUse {
validDelegate.photoPicker(self, didSelectImage: validImage)
}
picker.dismissViewControllerAnimated(true, completion: nil)
}
}
</code></pre>
imagePickerControllerDidCancel is pretty straightforward, the only other method that you need would be imagePickerControllerDidFinishPickingMediaInfo, here you handle the image handed back to the delegate. Following standard documentation, you determine the mediatype that was selected, remember it could be a movie file, not just a photo. In our case we just want images. Then decide do you care about the edited image, did you allow image editing in the setup of the controller? Here's where you deal with that. Finally cast the image you want to an optional UIImage. Notice I then call another delegate (of this container class), indicating the image is ready to go and is valid. Now, here's really the last piece of functionality needed.<br />
The user of your container class needs a way to get the image when it's all said and done and ready to give to a viewController and View. So lets go back to the top of your class file and create a protocol that declares a delegate method for use with your new class.<br />
<pre><code>protocol PhotoPickerDelegate: class {
func photoPicker(picker: PhotoPickerController, didSelectImage image: UIImage)
}
</code></pre>
Now all you need to do is simply make your UIViewController or whatever else is using your class abide by this protocol. You could also use NSNotifications as well for even looser coupling, but I think the delegate pattern works fine for this.<br />
Lastly, you need to implement this one method for the UINavigationControllerDelegate<br />
<pre><code>/** UINavigationControllerDelegate is required to ensure the UIImagePickerController has a light status bar instead of black */
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent
}
</code></pre>
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com0tag:blogger.com,1999:blog-3606887666975536518.post-20046455036253357592015-10-28T20:06:00.000-07:002015-10-28T20:06:58.319-07:00Prefer Swift's for-in loop over traditional C for loop<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>I'm sure most of us started our first programming adventures in C.
How many times</title>
</head>
<body>
<p>I'm sure most of us started our first programming adventures in C.</p>
<p>How many times have you written</p>
<pre><code>for (int i = 0; i < blah; i++)
</code></pre>
<p>or something similar in countless methods, functions, etc.?</p>
<p>In C, C++, Javascript, Java, it's ubiquitous.</p>
<p>Then I came upon the most glorious programming language ever created, Ruby</p>
<pre><code>for index in 0..5
puts "Value of local variable is #{i}"
end
</code></pre>
<p>This is obviously equivalent to:</p>
<pre><code>for (int index = 0; i <= 5; i++)
</code></pre>
<p>The ease of reading should be obvious in Ruby's typical verbosity. Not that any programmer worth his/her salt can't immediately decipher a traditional for loop.</p>
<p>The idea though is to flow code in a way we read natural language.</p>
<p>So it was no suprise that Swift adopted this for-in loop pattern, and in all cases you should prefer to use this format over the C for loop.</p>
<p>Here's Swift's for-in</p>
<pre><code>for index in 0...5 {
print("current index is \(index)")
}
</code></pre>
<p>Now notice something slightly different</p>
<p>.. vs. ...</p>
<p>In Ruby .. means inclusive (in the example above 0 to 5 including 5). If you added one more dot, ... you'd get exclusive, meaning 0 to 5 excluding 5 (0,1,2,3,4).</p>
<p>In Swift, not the case, ... means inclusive. There currently isn't an exclusive dot offering, although when Swift was first released I remember there being 2 options. This makes sense, in reality if you need exclusive use, you juse use 1 less in value for your range maximum.</p>
<p>You even have the option to just exclude the variable name if it's not needed.</p>
<pre><code>for _ in 0...5 {
print("Hello")
}
</code></pre>
<p>Just remember, that will print 6 not 5 times. A better visualization when you want to do something a set number of times would be to start with 1, 1...5 (visualize needing to do something 5 times).</p>
<p>A good example that I'm currently using that to me reads better is parsring rows and columns in an app:</p>
<pre><code>for rowIndex in 0...self.rows {
for columnIndex in 0...self.columns {
// now you have each row and column index.
}
}
</code></pre>
<p>Having said that there are without a doubt instances where you need to use a C for loop.</p>
<p>Swift's is slightly different:</p>
<pre><code>for var index = 0; index < 10; index += 2 {
print("index is \(index)")
}
</code></pre>
<p>Imagine you need to increment by 2, or multiply by 2 each time, or decrease in value, etc.</p>
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com0tag:blogger.com,1999:blog-3606887666975536518.post-78112993492101102172015-09-16T09:15:00.001-07:002015-09-16T09:20:03.515-07:00Using Xamarin Android Player with Android Studio<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>Android Studio and it's accompanying emulator have actually improved considerably. I'd even say the emulator</title>
</head>
<body>
<p>Android Studio and its accompanying emulator have actually improved considerably. I'd even say the emulator that ships now is perfectly sufficient to use, although there's obviously the better alternative(s) like GenyMotion.</p>
<p>Having said that, the Xamarin Android Player is probably the best out there for a free fast booting emulator.</p>
<p>First install the XAP, no need to install Xamarin Studio.</p>
<p>Launch Android Studio, have your project ready to launch on an emulator.</p>
<p>Here's thing, the running XAP (after you create a device and press play) will not show up in Android Studios list of devices in the AVD. Don't fret, as it won't matter.</p>
<p>When you finally push the run button you will get a screen like this with an option to now launch on the XAP:</p>
<p><img src="http://i.imgur.com/BsqONEj.png?2" alt="image" /></p>
<p>Now you can use the XAP for your project :)</p>
<p><img src="http://i.imgur.com/lliWhjFl.png" alt="image" /></p>
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com51tag:blogger.com,1999:blog-3606887666975536518.post-89032696181195972432015-09-11T07:35:00.001-07:002015-09-11T07:35:45.429-07:00Simple Xamarin iOS Keychain code<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>I had searched and found a few decent examples of KeyChain (iOS) usage in Xamarin</title>
</head>
<body>
<p>I had searched and found a few decent examples of KeyChain (iOS) usage in Xamarin but not exactly the code I was happy with.</p>
<p>So this is more of a mashup of pieces of the good code I found formed into one utility class.</p>
<p>The key essentials are find an existing key, create a new key, delete a previous key. The examples I saw tried to do all of this in one method, it's better to break things up, have one method per responsilibity.</p>
<pre><code>using Security;
using Foundation;
public class KeyChain
{
public string ValueForKey(string key)
{
var record = ExistingRecordForKey (key);
SecStatusCode resultCode;
var match = SecKeyChain.QueryAsRecord(record, out resultCode);
if (resultCode == SecStatusCode.Success)
return NSString.FromData (match.ValueData, NSStringEncoding.UTF8);
else
return String.Empty;
}
public void SetValueForKey(string value, string key)
{
var record = ExistingRecordForKey (key);
if (value.IsNullOrEmpty())
{
if (!ValueForKey(key).IsNullOrEmpty())
RemoveRecord(record);
return;
}
// if the key already exists, remove it
if (!ValueForKey(key).IsNullOrEmpty())
RemoveRecord(record);
var result = SecKeyChain.Add(CreateRecordForNewKeyValue(key, value));
if (result != SecStatusCode.Success)
{
throw new Exception(String.Format("Error adding record: {0}", result));
}
}
private SecRecord CreateRecordForNewKeyValue(string key, string value)
{
return new SecRecord(SecKind.GenericPassword)
{
Account = key,
Service = ServiceName,
Label = key,
ValueData = NSData.FromString(value, NSStringEncoding.UTF8),
};
}
private SecRecord ExistingRecordForKey(string key)
{
return new SecRecord(SecKind.GenericPassword)
{
Account = key,
Service = ServiceName,
Label = key,
};
}
private bool RemoveRecord(SecRecord record)
{
var result = SecKeyChain.Remove(record);
if (result != SecStatusCode.Success)
{
throw new Exception(String.Format("Error removing record: {0}", result));
}
return true;
}
}
</code></pre>
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com28tag:blogger.com,1999:blog-3606887666975536518.post-31749581574100463772015-04-30T10:57:00.000-07:002015-04-30T11:07:34.546-07:00Xamarin Studio Key bindings for the Xcode userI was tired of switching machines using Xamarin Studio and having to reset all my keybindings.
Because I'm so used to Xcode keybindings, I did my best to make the same similar key bindings for XS, so here you can grab them, make them your own:
<br />
<br />
<a href="https://github.com/markawil/XamarinStudio-KeyBindings/tree/master">https://github.com/markawil/XamarinStudio-KeyBindings/</a>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com2tag:blogger.com,1999:blog-3606887666975536518.post-19800953332380663792015-04-22T07:36:00.000-07:002015-04-22T07:36:49.222-07:00Simple C# Dependency Resolver, or the beginning of your own IoC container<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>It's kind of pointless to write your own IoC container in C# seeing that there's</title>
</head>
<body>
<p>It's kind of pointless to write your own IoC container in C# seeing that there's probably a 100 out there at this point. With that said, there are occasions like the project I'm in now where you plan on some point pulling in a popular controller, but you need something basic to register and resolve instances of interfaces throughout the existing code base in the mean time.</p>
<p>The idea is this:</p>
<p>You have viewModels or controllers that need services, clients, other controllers, whatever.</p>
<p>You could just not care about clean code and do this:</p>
<pre><code>public class MainViewModel()
{
private readonly IService _service;
private readonly IDataSource _source;
public MainViewModel() {
_service = new Service();
_source = new Source(service);
}
void go() {
_service.CallAPI();
}
}
</code></pre>
<p>No big deal. But you start doing this in multiple controllers, viewModels, and then the issue comes up where now you've changed the IDataSource instance you want to use to</p>
<pre><code>new SQLiteSource(service);
</code></pre>
<p>So you either go through each class where you're instantiating this Source and change the line, or do what you should have done from the get go following SOLID principles and make the change in one place.</p>
<p>This example below is what you'd do in a Xamarin.Forms app. You start at the base of the project structure, so for Xamarin it's a class called App.</p>
<pre><code>public class App : Application
{
public App()
{
registerDependencies();
var mainView = new MainView();
var navPage = new NavigationPage(mainView);
this.MainPage = navigation;
}
void registerDependencies() {
DependencyResolver.RegisterInstance<IService>(new LoginService());
var service = DependencyResolver.Resolve<IService>();
DependencyResolver.RegisterInstance<IDataSource>(new SQLiteSource(service));
}
}
public class MainViewModel()
{
private readonly IService _service;
private readonly IDataSource _source;
public MainViewModel() {
_service = DependencyResolver.Resolve<IService>();
_source = DependencyResolver.Resolve<IDataSource>();
}
void go() {
_service.CallAPI();
}
}
</code></pre>
<p>That's it. Now any class that needs an implementation of an interface (of course you need to register at the startup), you just pass the responsibility to your Resolver class, which is below:</p>
<pre><code>public static class DependencyResolver
{
private static readonly Dictionary<Type, object> _map = new Dictionary<Type, object>();
public static void RegisterInstance<T>(object instance) {
if (!_map.ContainsKey(typeof(T))) {
_map.Add (typeof(T), instance);
}
}
public static T Resolve<T>() {
if (_map.ContainsKey(typeof(T))) {
return (T)_map [typeof(T)];
} else {
throw(new KeyNotFoundException ());
}
}
}
</code></pre>
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com4tag:blogger.com,1999:blog-3606887666975536518.post-12106701786766091582015-03-31T21:36:00.000-07:002015-03-31T21:37:30.670-07:00Gradient UINavigationBar in Swift<html>
<head>
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>Here's how to make a gradient NavBar in Swift,
taken mainly from this <a href="http://stackoverflow.com/questions/494982/uinavigationbar-tintcolor-with-gradient">SO post</a>:
First create an extension for CAGradientLayer</title>
</head>
<body>
Here's how to make a gradient NavBar in Swift:<br />
First create an extension for CAGradientLayer (need to add Quartz library)<br />
<pre><code>extension CAGradientLayer {
class func gradientLayerForBounds(bounds: CGRect) -> CAGradientLayer {
var layer = CAGradientLayer()
layer.frame = bounds
layer.colors = [UIColor.redColor().CGColor, UIColor.blueColor().CGColor]
return layer
}
}
</code></pre>
Use whatever colors suit your needs.<br />
Then in your overriden NavController class (so many ways to do this, I chose to set it up in the NavController subclass used everywhere in my app),<br />
<pre><code>private func imageLayerForGradientBackground() -> UIImage {
var updatedFrame = self.navigationBar.bounds
// take into account the status bar
updatedFrame.size.height += 20
var layer = CAGradientLayer.gradientLayerForBounds(updatedFrame)
UIGraphicsBeginImageContext(layer.bounds.size)
layer.renderInContext(UIGraphicsGetCurrentContext())
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
</code></pre>
In your viewDidLoad of the NavController subclass:<br />
<pre><code>override func viewDidLoad() {
super.viewDidLoad()
self.navigationBar.translucent = false
self.navigationBar.tintColor = UIColor.whiteColor()
let fontDictionary = [ NSForegroundColorAttributeName:UIColor.whiteColor() ]
self.navigationBar.titleTextAttributes = fontDictionary
self.navigationBar.setBackgroundImage(imageLayerForGradientBackground(), forBarMetrics: UIBarMetrics.Default)
}
</code></pre>
I did some whitening to the tint and title text, mainly because any gradient you have, white would probably work best.<br />
Here's the current app I'm working on with the gradient colors of my choice:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv5a9UzE3TIBSzstHQUfETaNNsqs04tjTPa3Xzj5aygTj2tcnGkPOLCsZjDLCLWP2m2Ghjo0CqrGE_RhDqYEYrVa8WIj30WTdnPD2pA4hi5zcf2gVw-jVqg-kYOPpVxbrEyPWILpgsjdxL/s1600/navBarGradient.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv5a9UzE3TIBSzstHQUfETaNNsqs04tjTPa3Xzj5aygTj2tcnGkPOLCsZjDLCLWP2m2Ghjo0CqrGE_RhDqYEYrVa8WIj30WTdnPD2pA4hi5zcf2gVw-jVqg-kYOPpVxbrEyPWILpgsjdxL/s320/navBarGradient.png" /></a></div>
<br />
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com5tag:blogger.com,1999:blog-3606887666975536518.post-21936694459662421532015-03-29T18:00:00.002-07:002015-03-29T18:00:47.147-07:00C# Model Object builderA nice online tool to build C# model objects based off JSON text you feed it.<br />
<br />
<a href="http://json2csharp.com/">http://json2csharp.com/</a>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com0tag:blogger.com,1999:blog-3606887666975536518.post-6704979019367114672015-03-29T17:37:00.001-07:002015-03-29T17:37:47.733-07:00How to shuffle an array in Swift<html>
<head>
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>4-2-2015</title>
</head>
<body>
This was imported over from my roon.io blog that's now been closed down. <br /><br />
Had the challenge and time limit put to me the other day so here’s my working solution:<br />
<pre><code>func shuffleArray(array: [Int]) -> [Int] {
var tempArray = array
for index in 0...array.count - 1 {
let randomNumber = arc4random_uniform(UInt32(myArray.count - 1))
let randomIndex = Int(randomNumber)
tempArray[randomIndex] = array[index]
}
return tempArray
}
shuffleArray(myArray)
shuffleArray(myArray)
shuffleArray(myArray)
</code></pre>
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com2tag:blogger.com,1999:blog-3606887666975536518.post-41775212698596538722015-03-29T17:32:00.000-07:002015-03-29T17:43:56.847-07:00Parsing a date out of JSON in Swift<html>
<head>
<style>
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
<title>For most of the APIs you'll deal with you'll get the date back in a</title>
</head>
<body>
For most of the APIs you'll deal with you'll get the date back in a format like this:<br />
date:1420420409680<br />
In Objective-C it was pretty easy assume the interval is the value above,<br />
<pre><code>NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval/1000.0];
NSDateFormatter* df_local = [[NSDateFormatter alloc] init];
[df_local setTimeZone:[NSTimeZone timeZoneWithName:@"CST"]];
[df_local setDateFormat:@"MM-dd"];
NSString* ts_local_string = [df_local stringFromDate:date];
</code></pre>
This would give you a formatted date string in the timezone you request.<br />
In Swift it wasn't as straight forward.<br />
Originally I attempted this:<br />
<pre><code>var meetups = [Meetup]()
for meetupDictionary in (meetupsJsonArray as Array<Dictionary<String, AnyObject>>) {
let eventName = meetupDictionary[self.nameKey]! as String
let eventId = meetupDictionary[self.idKey]! as String
let timeValue = meetupDictionary[self.timeKey]! as Int
let timeValueAsDouble = Double(timeValue/1000.0)
let date = NSDate(timeIntervalSince1970: timeValueAsDouble)
let meetup = Meetup(title: eventName, eventId: eventId, date: date)
meetups.append(meetup)
}
</code></pre>
That worked, actually (well not the timezoning, but the date-time anyway).<br />
But only on a 64 bit device/simulator. On an iPhone 5/4s it was giving a strange value for the year. As you would guess, it had to do with as Int. I won't explain it here, but the blog sketchyTech explains how numbers and primitives are handled in Swift.<br /><br />
<a href="http://sketchytech.blogspot.com/2014/10/swift-by-numbers-long-and-short-of-it.html">Swift by the numbers, the long and short of it</a><br/><br/>
The correct way was to change the time parsing lines to this:<br />
<pre><code>let timeValueAsNSNumber = meetupDictionary[self.timeKey]! as NSNumber
let timeValue = timeValueAsNSNumber.doubleValue/1000.0
let date = NSDate(timeIntervalSince1970: timeValue)
</code></pre>
Even with the new offerings of Swift, you still have to use aspects of the CocoaTouch framework like NSNumber. This gave the correct date and time on a 32 and 64 bit devices.<br />
</body>
</html>Mark Whttp://www.blogger.com/profile/13844023674115634171noreply@blogger.com0