Swift5.1.3 Xcode11.3.1 SwiftUI
- Twitterのツイート文を自動で作成
- ランダム関数でテキストエリアに文章を反映
- CSVをXcodeに取り込みオート文の素材にします
「以下は動画のハイライトです。」
Twitterの投稿を自動でロボットに任せるサービスは色々とありますが、どのような技術が使われているのでしょうか。有名なものではCSVなどで雛形を作り、文章の要素を組み合わせてツイート文を作成する類のものです。
今回は初心者でもこうしたロボットの仕組みを学べるように簡単なSwiftUIのコードでiPhoneアプリを作ってみたいと思います。
まず使う変数は以下です。
@State var csvArr = [String]()
@State var elements0 = [String]()
@State var elements1 = [String]()
@State var elements2 = [String]()
@State var elements3 = [String]()
@State var elements4 = [String]()
@State var text = ""
csvArrにCSVファイルの文字情報が格納されます。この動きを復習したい方は第36回の単語帳アプリを作る動画をご査収ください。
let url = Bundle.main.path(forResource: "fileJap", ofType: "csv")
do {
var csvString = try String(contentsOfFile: url!, encoding: String.Encoding.utf8)
self.csvArr = csvString.components(separatedBy: .whitespacesAndNewlines)
print("before", self.csvArr)
self.csvArr = self.csvArr.filter{!$0.isEmpty}
self.csvArr.removeFirst()
print("after", self.csvArr)
} catch let error as NSError {
print("Error: \(error)")
return
}
for sstr in self.csvArr {
let arrayPart = sstr.components(separatedBy: ",")
self.elements0.append(arrayPart[0])
self.elements1.append(arrayPart[1])
self.elements2.append(arrayPart[2])
self.elements3.append(arrayPart[3])
self.elements4.append(arrayPart[4])
}
CSVにはいつ、どこで、誰が、何を、どうしたの各パーツが用意されております。この雛形は適宜自分で変えてみてください。この雛形が変数elements0
~ 4に代入されて後にランダム関数で組み合わせれます。
ちょっと注意が必要な箇所は以下です。
print("before", self.csvArr)
self.csvArr = self.csvArr.filter{!$0.isEmpty}
self.csvArr.removeFirst()
print("after", self.csvArr)
Before, Afterで文章がどう変わるかご確認ください。MacでCSVファイルを編集すると予期せぬところに空白が入ってしまったりします。これはfilter{!$0.isEmpty}で除去しているのですが、もしかしたらもっといい記述方法があるかもしれません。また私はわかりやすくCSVにヘッダーをつけているため、第一行はremoveFirst()で削除しております。
取り出した文章のパーツは以下のように結合させます。
let rInt0 = Int.random(in: 0..<self.elements0.count)
let rInt1 = Int.random(in: 0..<self.elements1.count)
let rInt2 = Int.random(in: 0..<self.elements2.count)
let rInt3 = Int.random(in: 0..<self.elements3.count)
let rInt4 = Int.random(in: 0..<self.elements4.count)
self.text = "\(self.elements0[rInt0])\(self.elements1[rInt1])\(self.elements2[rInt2])\(self.elements3[rInt3])\(self.elements4[rInt4])"
rInt1 ~ 5にランダム値が代入されます。最終的に変数textに組み合わせてString化するのですがこれは以下のテキストエリアに反映されるので完成後、ちょっと直したい場合はそのままTextAreaで編集することが可能です。
TextArea(
text: $text
).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
struct TextArea: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextView {
let myTextArea = UITextView()
myTextArea.delegate = context.coordinator
myTextArea.font = UIFont(name: "HelveticaNeue", size: 25)
myTextArea.backgroundColor = UIColor(displayP3Red: 0.8, green: 0.8, blue:
0.0, alpha: 0.2)
return myTextArea
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator : NSObject, UITextViewDelegate {
var parent: TextArea
init(_ uiTextView: TextArea) {
self.parent = uiTextView
}
func textViewDidChange(_ textView: UITextView) {
self.parent.text = textView.text
}
}
}
おまけとしてTwitterへのリンクのWebViewを作成しております。テキストエリアのtextをコピーしてSheetViewに表示されるTwitterのページから投稿してみてください。
struct WebView : UIViewRepresentable {
var url: URL
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ uiView: WKWebView, context: Context) {
let request = URLRequest(url: url)
uiView.load(request)
}
}
struct SheetView: View {
@State private var showTrigger = false
var body: some View {
VStack {
Button("Twitter") {
self.showTrigger = true
}
}.sheet(isPresented: $showTrigger, onDismiss: {
print("Show TwitterView")
}) {
TwitterView()
}
}
}
struct TwitterView: View {
@Environment(\.presentationMode) var presentation
@State var urlString:String = "https://twitter.com"
var body: some View {
VStack {
WebView(url: URL(string: urlString)!)
Spacer()
Button("Close") {
self.presentation.wrappedValue.dismiss()
}
Spacer()
}.font(.custom("SFProText-Bold", size: 25))
}
}
完成したContentViewは以下のようになります。上部のボタンを押すたびに自動でツイート文が作成されます。この隣のボタンからTwitterのホームページに移行して投稿します。Closeボタンを押すと元の画面に戻ります。
struct ContentView: View {
@State var csvArr = [String]()
@State var elements0 = [String]()
@State var elements1 = [String]()
@State var elements2 = [String]()
@State var elements3 = [String]()
@State var elements4 = [String]()
@State var text = ""
var body: some View {
VStack(spacing:50) {
HStack(spacing:50) {
Button(action:{
let rInt0 = Int.random(in: 0..<self.elements0.count)
let rInt1 = Int.random(in: 0..<self.elements1.count)
let rInt2 = Int.random(in: 0..<self.elements2.count)
let rInt3 = Int.random(in: 0..<self.elements3.count)
let rInt4 = Int.random(in: 0..<self.elements4.count)
self.text = "\(self.elements0[rInt0])\(self.elements1[rInt1])\(self.elements2[rInt2])\(self.elements3[rInt3])\(self.elements4[rInt4])"
}) {
Text("Random Message")
}
SheetView()
}
TextArea(
text: $text
).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
.onAppear(
perform: {
let url = Bundle.main.path(forResource: "fileJap", ofType: "csv")
do {
var csvString = try String(contentsOfFile: url!, encoding: String.Encoding.utf8)
self.csvArr = csvString.components(separatedBy: .whitespacesAndNewlines)
print("before", self.csvArr)
self.csvArr = self.csvArr.filter{!$0.isEmpty}
self.csvArr.removeFirst()
print("after", self.csvArr)
} catch let error as NSError {
print("Error: \(error)")
return
}
for sstr in self.csvArr {
let arrayPart = sstr.components(separatedBy: ",")
self.elements0.append(arrayPart[0])
self.elements1.append(arrayPart[1])
self.elements2.append(arrayPart[2])
self.elements3.append(arrayPart[3])
self.elements4.append(arrayPart[4])
}
}
)
.font(.system(size:30))
}
}
ソースコードはYouTubeのコメント欄に記載します。
目次へ戻る