回溯解决电话拨号字母组合,swift:Subscripts 下标的花式玩法,swift5 Auto Layout 入门,John 易筋 ARTS 打卡 Week 29

用户头像
John(易筋)
关注
发布于: 2020 年 12 月 06 日

1. Algorithm: 每周至少做一个 LeetCode 的算法题

笔者的文章:

算法:回溯解决电话拨号中的字母组合Letter Combinations of a Phone Number

题目

17. Letter Combinations of a Phone Number



Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order.



A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.





Example 1:



Input: digits = "23"
Output: ["ad","ae","af","bd","be","bf","cd","ce","cf"]



Example 2:



Input: digits = ""
Output: []



Example 3:



Input: digits = "2"
Output: ["a","b","c"]



Constraints:



0 <= digits.length <= 4
digits[i] is a digit in the range ['2', '9'].



回溯解法

回溯 是一种通过探索所有潜在候选者来找到所有解决方案的算法。如果候选解决方案不是解决方案(或至少不是最后一个解决方案),则回溯算法会通过在上一步(即 回溯)上进行一些更改来丢弃它,然后再试一次。



这是一个回溯功能backtrack(combination, next_digits) ,它将正在进行的字母组合和接下来要检查的数字作为参数。



  • 如果没有更多数字可检查,则表示当前组合已完成。

  • 如果还有数字要检查:遍历映射下一个可用数字的字母。

将当前字母追加到当前组合 combination = combination + letter

继续检查下一个数字: backtrack(combination + letter, next_digits[1:])



class Solution:
def letterCombinations(self, digits: str) -> List[str]:
numberMap = {
"2": ["a", "b", "c"],
"3": ["d", "e", "f"],
"4": ["g", "h", "i"],
"5": ["j", "k", "l"],
"6": ["m", "n", "o"],
"7": ["p", "q", "r", "s"],
"8": ["t", "u", "v"],
"9": ["w", "x", "y", "z"]
}
result = []
def backtrack(combination: str, nextDigits: str):
if len(nextDigits) == 0:
result.append(combination)
return
else:
for item in numberMap[nextDigits[0]]:
backtrack(combination + item, nextDigits[1:])
if digits:
backtrack("", digits)
return result



逐层往下解法

根据回溯的解法,当前层级的结果可以当做下个层级的输入,所以可以通过顺序的思维解法如下。这里需要注意,如果digits不为空,需要初始第一个值为空支付窜"".

class LetterCombinationsOfAPhoneNumber:
def letterCombinations(self, digits: str) -> List[str]:
numberMap = {
"2": ["a", "b", "c"],
"3": ["d", "e", "f"],
"4": ["g", "h", "i"],
"5": ["j", "k", "l"],
"6": ["m", "n", "o"],
"7": ["p", "q", "r", "s"],
"8": ["t", "u", "v"],
"9": ["w", "x", "y", "z"]
}
result = []
if len(digits) == 0:
return result
# for first item to combine
result.append("")
preResult = []
for s in digits:
preResult, result = result, []
for i in numberMap[s]:
for k in preResult:
result.append(k + i)
return result



2. Review: 阅读并点评至少一篇英文技术文章

swift:Subscripts

https://docs.swift.org/swift-book/LanguageGuide/Subscripts.html



swift中的下标Subscripts的用法,除了常规Array, Dictionay 根据key值获取value外,还可以定制get和set,脑洞比较大的地方在于对象也可以设置下标。比如下面的代码,定制了下标的get方法,返回一个乘积的结果。

struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// Prints "six times three is 18"

更大的脑洞在于,校验对象的init值,比如下面的矩阵可以校验是否越界



struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValid(row: row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(row: row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
let someValue = matrix[2, 2]
// This triggers an assert, because [2, 2] is outside of the matrix bounds.





3. Tips: 学习至少一个技术技巧

笔者的文章:

Xcode 快捷键大全 2020 - 持续更新

Playground

  • Playground运行 Command-Shift-Return

面板

  • 左侧面板 command + 0

  • 右侧面板 command + option + 0

  • 底部面板 command + shift + Y

代码, 文档

  • 注释 command + option + /

  • 代码补全 esc

  • 格式化代码control + I

  • 查看定义 control + command + J

  • 查看引用 control + command + shift + H

  • 重命名 control + command + E

  • 查看 Apple 文档 command + shift + 0

运行,调试

  • 运行 command + R

  • 构建 command + B

  • 停止运行或构建 command + .

  • 清除构建目录 command + shift + K

  • 清除控制台 command + K

  • 断点 command + L



定位

  • 快速查找打开类(文件名、或方法名搜索) command + shift + O

  • 快速定位当前类在项目文件中的位置 command + shift + J

  • 类文件 h 与 m 之间切换 control + command + ↑/↓

  • 切当前页面的兄弟页面 | 方法 control + 5 | 6

  • 光标去行首 control + A | command + ←

  • 光标去行尾 control + E | command + →

  • 光标去文件顶部/底部 command + ↑/↓

  • 删除左侧剩余字符 command + delete

  • 删除右侧剩余字符 control + K

  • 选中的代码左移 command + [

  • 选中的代码右移 command + ]

  • 选中的代码上移 option + command + [

  • 选中的代码下移 option + command + ]

  • 收起方法体或类 option + command + ←

  • 展开方法体或类 option + command + →

  • 回到上一个打开的页面 control + command + ←

  • 回到上一个打开的页面 control + command + →

  • 下一个 command + g

  • 上一个 command +shift + g

文件

  • 新建文件 command + N

  • 添加文件 option + command + A

  • 新建组文件夹 option + command + N

  • 新窗口打开当前工程 command + shift + T

  • 全屏或退出全屏 control + command + F

  • 在当前文件中查找 command + F

  • 在当前文件查找并替换 option + command + F

  • 在工作空间中查找 command + shift + F

  • 在工作空间中查找并替换 option + command + shift + F



Xcode 使用 TODO、FIXME、!!!、???、MARK标记用法

// MARK: 标记,和#pragma mark效果类似
// TODO: 标示处有功能代码待编写
// FIXME: 标示处代码需要修正
// !!!: 标示处代码需要注意(警告)
// ???: 标示处代码有疑问 (这里代码是个坑)



参考

https://github.com/bingoogolapple/bingoogolapple.github.io/issues/212



https://juejin.cn/post/6844904198622937101



4. Share: 分享一篇有观点和思考的技术文章

笔者博客:

翻译: swift5 iOS中的自动布局教程:Auto Layout入门

说明

对于新的iOS开发人员,以下是自动版式的快速概述:



最初,Apple为iPhone制作了一个屏幕大小。开发人员不必创建灵活的界面,因为他们只需要适应那种尺寸即可。如今,不同尺寸的设备以及对横向模式的更多重视要求使用不同尺寸的用户界面。自动布局是Apple解决此问题的解决方案,它可以使UI元素根据屏幕大小进行增长,缩小和移动。



在本教程的后面,您将研究一个名为Gallery Kit的项目。要访问所需的资料,请单击教程顶部或底部的“下载资料”按钮。在进入项目之前,熟悉自动布局很重要。



适应自动布局

在创建用户界面之前,请浏览Xcode和Interface Builder。Interface Builder是Xcode中的图形工具,允许开发人员使用自动布局创建UI。以下是使用Interface Builder时会遇到的一些常见功能:



“添加新约束”菜单位于编辑器的右下方。使用此菜单可以向按钮和标签之类的UI元素添加新的约束。

该对齐菜单到左的添加新的约束菜单。此菜单创建对齐约束。使用此菜单可以使标签相对于另一个视图垂直对齐。

该文档大纲是在左侧。使用此面板可以查看视图布局的层次结构。在确定视图的关系时,这很有用。

在属性检查器是在Xcode中右侧中间的实用工具面板。使用此面板可自定义视图的属性,例如在更改视图的背景色或按钮的文本时。

T形条是Xcode可视化视图约束的方式。在下图中,有三个T形条,分别表示按钮的顶部,前部和尾部约束。这些条还分别通过变为黄色或红色来指示任何警告或错误。

一个简单的例子

要开始了解Interface Builder的来龙去脉,请首先创建一个空的iPhone应用程序。

打开Xcode,选择“创建新的Xcode项目”,然后选择“ Single View App”模板。

输入按钮的产品名称。将其他选项保留为默认值,然后执行下一步以创建项目。



选择Main.storyboard,然后在文档大纲中选择View Controller Scene。确保在情节提要的文件检查器中启用“使用自动布局”,“使用特征变化”和“使用安全区域布局指南” :

iOS 11的新功能:“安全区域布局指南”可让您知道在导航或其他栏可能遮挡的所有内容下方可见的内容区域。



现在该弄脏你的手了!适应自动版式的最佳方法是创建用户界面。准备?组?走!

动态按钮

单击窗口栏中的库按钮。查找“按钮”行–搜索单词“按钮”更容易。在主窗口区域中,将一个按钮拖到代表您的视图控制器的白色矩形中。拖入第二个按钮并将其放置在第一个按钮下方。

现在,您将更改按钮的背景色。确保检查器面板处于打开状态,单击“属性”检查器,然后在“视图”部分中找到“背景”选项。为上方的按钮提供绿色背景,为下方的按钮提供黄色背景。

选择绿色按钮,然后使用右下角的“添加新约束”菜单,然后输入40以对其最近的下一个邻点进行40点约束。注意红色的I-bar;单击此按钮将在该方向上添加或删除约束。选择“添加1约束”以实际创建按钮的约束。现在,选择黄色按钮,然后输入8以对视图控制器的底部进行8点约束。不要忘记选择Add 1 Constraint。

打开“ 对齐”菜单,选择黄色按钮,然后选中“在容器中水平放置”,然后单击“添加1个约束”。现在,使用Shift键同时选择两个按钮,然后在“对齐”菜单中选中“前缘”。再次,通过单击添加1约束实际安装约束。

您可能会在左上角看到一个带有箭头的红色圆圈。通常,这表示您需要解决的问题。现在不用担心。您稍后将修复它。:]



现在,您将看到它在运行时如何工作。将以下方法添加到ViewController.swift中的类:



@IBAction func buttonTapped(_ sender: UIButton) {
if sender.title(for: .normal) == "X" {
sender.setTitle("A very long title for this button", for: .normal)
} else {
sender.setTitle("X", for: .normal)
}
}

这会在触发事件的按钮的长标题和短标题之间切换。将此操作方法连接到Interface Builder中的两个按钮。按住Control键将每个按钮拖到“文档大纲”中的视图控制器,然后在弹出窗口中选择buttonTapped:



生成并运行该应用程序,然后点击按钮以查看其行为。以纵向和横向执行测试。

无论哪个按钮的标题是长还是短,布局都可以满足您所赋予的约束:



  • 下部按钮在窗口中水平居中对齐。

  • 下方的按钮距离窗口底部8个位置。

  • 顶部按钮在下部按钮上方40点,并且与下部按钮对齐。



这就是用户界面的整个规范。

实验时间

为了娱乐,请删除“前导对齐”约束。为此,请在“

文档大纲”中选择它,然后按键盘上的Delete键。然后,在Interface Builder中选择两个按钮,然后从Align菜单中选择Trailing Edges选项。

现在再次运行该应用程序,并注意差异。



现在,删除尾随路线约束,并选择两个按钮,然后选择“对齐‣水平中心”。这将使顶部按钮相对于底部按钮居中。运行该应用程序,然后查看点击按钮时的行为。

自动布局问题:有时Xcode无法自动解决您要定义的布局。在大多数情况下,Xcode都没有机会重新计算视图,并且您会陷入一个橙色框,该框表明布局的最佳猜测。在这种情况下,单击“更新框架”按钮应该可以解决该问题。



有时候,这个问题可能很难解决。一直选择右边的“解决自动布局问题”按钮,以查看选项菜单,这些菜单可以通过更新现有约束,添加缺失的约束,将约束重置为Xcode建议的约束或清除约束来帮助您重新开始。 。

使用内在内容大小

“添加新约束”菜单具有“等宽”选项。如果在两个视图上都设置了此约束,则“自动版面配置”将使两个视图的宽度相等,以最大者为准。



选择两个按钮,然后选择添加新约束‣等宽。这为两个按钮添加了新的约束:

即使有两个T型条,在“文档大纲”中也显示为单个“等宽”约束:

运行该应用程序,然后点击按钮。无论标签上的标签最大,按钮的宽度始终相同。



当两个标签都短时,按钮将平均缩小。除非约束阻止,否则按钮将自行调整大小以适合其内容。按钮或标签知道它的宽度和高度,因为它知道所显示文本的长度和字体大小,如果是按钮,则知道文本与背景图像和一些填充的组合。这就是固有内容大小,这是自动版式中的一个重要概念。



您已经通过按钮看到了它的作用。自动版式会询问您的控件需要多大,并根据该信息对屏幕进行布局。通常,您想使用内部内容大小,但是在某些情况下,您可能不想这样做。在这些情况下,可以在视图上设置显式的宽度或高度约束。



游玩一下,以获得固定和对齐视图的感觉。请记住,您需要足够的约束以使“自动布局”可以确定所有视图的位置和大小。

付诸实践:图库示例

现在,您应该了解约束条件以及如何通过建立不同视图之间的关系来构建布局。在以下各节中,您将看到如何使用“自动版式”和约束来创建符合实际场景的版式。



假装您想要制作一个包含您最喜欢的程序员的画廊的应用程序。在横向和纵向上看起来像这样:



屏幕包括四个相等的四分之一。每个季度都有一个图像视图和一个标签。您将如何处理?



如果还没有,请下载Gallery Kit项目,然后打开入门项目。示例项目包含您需要在图库中显示的图像。



打开Main.storyboard,然后从左下角的“查看方式”面板中选择iPhone SE大小。

从“库”中,将一个普通的View对象拖到画布上。选择视图后,打开“大小”检查器,并将“宽度”设置为160,将“高度”设置为284点。

接下来,在“属性”检查器中,将视图的背景色设置为绿色:

将平原UIView放到情节提要上有两个原因。首先,您将使用它作为其他视图的容器,这有助于组织场景的内容。其次,它是自定义视图或控件的占位符。在第二种情况下,您还将其Class属性设置为您自己UIView或UIControl子类的名称。



选择绿色视图,打开“添加新约束”菜单,然后取消选中“约束到边距”。通过单击红色的I形条,在每个方向上为绿色视图的所有四个最近邻创建四个约束:

这将在绿色视图及其超级视图之间创建四个新的约束,每个约束用于视图的每一侧。实际的间距值可能会有所不同,具体取决于放置视图的位置。您不必更改值即可与上面的值匹配。单击添加4个约束以完成。



现在,您的情节提要板应如下所示:

安全区

您是否想知道为什么视图顶部的约束停在状态栏上,而不是一直到屏幕顶部?

从iOS 7开始,状态栏始终位于视图控制器的顶部-不再是单独的栏-那么有什么用呢?创建约束时,约束未附加到屏幕顶部,而是附加到了称为“安全区域”的不可见矩形的顶部。



安全区域是视图控制器的一部分,不会被状态栏,导航栏或标签栏之类的条遮挡。由于导航栏在横向上具有不同的高度,因此旋转设备时,安全区域会随导航栏调整大小。这样可以轻松地相对于导航栏放置视图。标签栏也是如此。



该视图需要四个约束条件才能保持不变。与按钮或标签不同,普通UIView字体没有固有的内容大小。您必须添加约束以确定每个视图的位置和大小。



在这种情况下,视图的大小由超级视图的大小隐含。此布局具有前导,尾随,顶部和底部约束,并且这些都有固定的长度。您可以在文档大纲中看到以下内容:

绿色视图的宽度由以下公式计算:安全区域的宽度减去(80 + 80);并通过以下公式计算其高度:安全区域的高度减去(13 + 163)。约束是固定的,因此视图只能调整大小。同样,您的值可能会有所不同,具体取决于放置视图的位置。



旋转应用程序时,超级视图的尺寸会发生变化,因此视图的大小也会随之变化。生成并运行该应用程序,然后旋转模拟器以查看视图的行为。



固定尺寸

您可能不总是希望设备旋转时调整视图的大小,因此可以使用约束为视图提供固定的宽度和/或高度。现在就做。



选择绿色视图,然后单击添加新约束。在弹出窗口中,选择“宽度”,并将其值设置为160;然后选择“高度”并将其值指定为372:

单击添加2个约束以完成。您已向视图添加了两个新约束,即160点宽度约束和372点高度约束。



通过从“文档大纲”中选择每个约束并在“大小”检查器中修改它们的值,还可以更改现有约束中的值。使用以下值:顶部:13,前导:80,尾部:80,底部:163。

运行应用程序。是的,肖像看起来不错。

现在旋转以在风景中看到它。哎呀!它不仅看起来不像您想要的那样,而且Xcode调试窗格转储了一个讨厌的错误消息,它看起来像这样:



Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this: (1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(...)
Will attempt to recover by breaking constraint....

还记得我说过必须有足够的约束条件,以便“自动版式”可以计算所有视图的位置和大小吗?好吧,这是一个约束太多的例子。当您收到错误消息“无法同时满足约束条件”时,表明您的约束条件存在冲突。



要解决此问题,请在文档大纲中选择“ Safe Area.trailing = View.trailing”,然后在底部删除“ Safe Area.bottom = View.bottom”,然后点击Delete。



故事板应如下所示:

现在,视图具有正确数量的约束来确定其大小和位置。运行应用程序,并验证错误消息是否消失以及旋转后视图是否保持相同大小。



接下来,选择绿色视图的高度约束,然后在“大小”检查器中将其“常量”更改为284。这将确保它的大小是屏幕的一半。

画肖像

从“库”中,将“标签”拖动到绿色视图上。请注意,现在,参考线出现在该绿色视图中,因为它是标签的超级视图。

将标签放在底部边缘,与导板等距。



现在,您需要添加一个空间约束,以将标签锚定在绿色视图的底部,左侧和右侧,相距20点。确保选择了标签,然后单击“添加新约束”按钮。为底部,左侧和右侧约束中的每个约束输入20,确保I-bar固定,然后选择添加3约束:

现在,在“属性”检查器中,选择“中心 对齐”。

对UILabels左右约束很重要。否则,当文本太长时,它们将显示在其父视图之外。



请注意,这些新约束在绿色视图的“约束”部分下列出,而不在主视图中列出。

添加图像

从库中,将一个新的图像视图对象拖到情节提要上,并使布局看起来像这样:

图像视图的顶部,左侧和右侧边缘固定到其超级视图,但其底部以8点的标准间距连接到标签的顶部。如果不确定如何执行此操作,请按照以下步骤操作。



1.将图像视图从“资源库”拖到绿色视图中。不必担心其大小或位置:

2.在选择“图像”视图的情况下,单击“添加新约束”,然后选择以下选项:

顶部,左侧和右侧I型杆设置为20点,而底部I型杆设置为8点。



您选择的约束导致的帧与图像视图的当前位置和大小不同。Interface Builder在添加约束时将自动调整框架。



现在,您可以为视图添加图像和名称了。您将使用Assets.xcassets中包含的捆绑图像。



仍在Main.storyboard中,选择Image视图,然后在Attributes检查器中将Ray设置为Image。还将“内容模式”设置为“宽高比适合”。然后,将背景设置为白色。



双击标签,并将其标题设置为Ray。



您的布局应如下所示:

优先事项

请注意,绿色视图内的约束变为红色。这是在您将图像设置在图像视图上时发生的。为什么您的布局无效?消除猜测。Xcode会告诉您出了什么问题。



单击文档大纲中“查看控制器场景”旁边的红色小箭头以查看问题:



您有内容优先级歧义错误。满嘴!含义是:如果图像视图和标签都没有固定高度,则自动布局不知道如果绿色视图的高度应该改变,则每个缩放比例要多少。



说,在某个时候,绿色视图会高出100点。自动版式应该如何在标签和图像视图之间分配这100个新点?标签保持相同大小时,图像视图是否会高出100点?还是在图像视图保持不变时标签变高?他们俩都额外获得50分,还是25 / 75、40 / 60或其他组合?



如果您不能解决此问题,则必须进行自动版面设计,结果可能无法预测。



解决方案是更改标签的“内容拥抱优先级”。您可以想象这里拥抱意味着合身。换句话说,视图的边界将拥抱内部内容的大小。此处的值越高,表示视图的增长可能性就越小,而保持不变的可能性就越大。



进入标签的大小检查器,并将“垂直内容拥抱优先级”设置为252。这使其比图像视图的优先级高一。结果,当超级视图更改大小时,图像视图将成为要调整大小的视图,并且标签将保持不变。

T型条应再次变为蓝色,并且自动布局警告应消失。

添加其他头

将绿色视图拖到主视图的左上角。回想一下,绿色视图具有水平和垂直空间限制,这些限制决定了其在父视图中的位置。它仍然具有这些,并且它们导致视图框架未对齐。

要解决此问题,请使用“解决自动布局问题”按钮,然后选择“更新约束常量”。这将更新约束以匹配框架:

现在,前导约束的大小为零,由窗口左边缘的粗蓝线表示。尽管视图位于拐角处,但它需要一些约束才能将其锚定在此处:

现在,您将开始添加更多视图以显示更多人。选择绿色视图,然后按Command-C,然后按Command-V进行复制。将重复项移到右上角:

请注意,T型杆为红色。制作副本时,它失去了对X和Y位置的约束。要解决此问题,请将视图固定在窗口的顶部和右侧。确保取消选中约束到边距。

再复制两次,然后将这些副本分别放在左下角和右下角。左下角视图应固定其前导和底部,而右下角视图应固定其后缘和底部边缘。



现在是时候让屏幕更彩色了。选择每个绿色视图,并将其背景更改为不同的颜色。还更改标签标题,并且图像查看图像以代表程序员。最后,您的屏幕应如下所示:

那些是好看的程序员!:]



在iPhone SE模拟器上运行该应用程序。纵向看起来不错,但横向却不好:

显而易见,出了什么问题:由于您在四个彩色容器视图上设置了固定的宽度和高度,因此无论其超级视图的大小如何,它们都将始终具有这些大小。



从所有四个视图中选择固定宽度和固定高度约束,并将其删除。这在文档大纲中最容易。如果您现在运行该应用程序,将会得到以下内容:

注意:由于固有内容的大小,某些视图比其他视图大。图像的大小决定了图像视图的大小。文本的大小决定标签的大小。加上边距的约束,就可以确定每个视图的总大小。

50:50分割

为了获得所需的布局,您需要将每个视图的宽度和高度设置为ViewController视图的50%。在文档大纲中,按住Control键从绿色的Ray视图拖动到“安全区域”视图:

在按Shift的同时,单击“相等宽度”和“相等高度”,然后按Enter。这使您可以选择多个项目。一旦激活了这些约束,Ray就会填满整个屏幕,这不是故意的。:]



在大小检查器中,单击“同级和祖先约束”部分中“与安全区域相等的宽度”行上的“编辑” :

在乘数字段中,输入0.5并按Enter键。这会将Ray视图的宽度设置为Ray容器视图的50%。对“等于安全区域的高度”行重复此操作。您应该看到Ray现在是正确的大小:

现在,对其余视图重复此操作。构建并运行。一切看起来都很棒!

然后去哪儿?

使用本教程顶部或底部的“下载材料”按钮下载项目的完整版本。



恭喜你!现在您知道了什么是自动版式,并且您对基本知识有了一定的了解!还有更多的东西要学习。为了继续学习,请查看我们的“自动布局”教程视频系列。



如果您在继续进行“自动布局”过程中有任何疑问或意见,请参加下面的论坛讨论。



翻译自

https://www.raywenderlich.com/811496-auto-layout-tutorial-in-ios-getting-started



发布于: 2020 年 12 月 06 日阅读数: 86
用户头像

John(易筋)

关注

问渠那得清如许?为有源头活水来 2018.07.17 加入

工作10+年,架构师,曾经阿里巴巴资深无线开发,汇丰银行架构师/专家。开发过日活过亿的淘宝Taobao App,擅长架构、算法、数据结构、设计模式、iOS、Java Spring Boot。易筋为阿里巴巴花名。

评论

发布
暂无评论
回溯解决电话拨号字母组合,swift:Subscripts下标的花式玩法,swift5 Auto Layout入门,John 易筋 ARTS 打卡 Week 29