SlideShare une entreprise Scribd logo
1  sur  36
Télécharger pour lire hors ligne
XSpect
Makes code reusable
and maintainable
2013/10/17
李岡諭 Xaree Lee (leondemon)
xareelee@gmail.com
Previously on
Cocoaheads@Taipei
Zonble's talk (about AOP)
http://goo.gl/4Rlbb2
羅馬不是一天造成的
Unmaintainable 的 code 也是
Life should be
simple, but...
1|
2|
3|

- (void)appendData:(NSData*)inData{
[_data appendData:inData];
}
Welcome to real life
1| - (void)appendData:(NSData*)inData{
2|
NSParameterAssert(inData != nil);
3|
NSParameterAssert([inData length]);
4|
if (!inData) {
5|
NSLog(@"inData is nil!");
for guarding and checking
6|
return;
7|
}
8|
if (![inData length]) {
9|
return;
10|
}
11|
NSInteger length = [_data length];
12|
[_lock lock];
for thread safe
13|
[_data appendData:inData];
main task
14|
[_lock unlock];
15|
NSParameterAssert(length != [_data length]);
16| #if DEBUG
for monitoring and analyzing
17|
[TestFlight passCheckpoint:@"APPEND_DATA"];
18| #else
19|
[Flurry logEvent:@"APPEND_DATA"];
20|
id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker];
21|
[tracker send:[[GAIDictionaryBuilder createEventWithCategory:@"data"
withAction:@"append" withLabel:@"user_data" withValue:nil] build]];
22| #endif
23| }
You add lots of code for
•確定傳入參數
•確定有插入資料
•加 lock
•加 Debug Log
•加 TestFlight Log、Flurry Log...

...and everywhere!
XSpect
Xaree's	 Spect	 library
spect: look, see
http://www.prefixsuffix.com
XSpect 包含了
2 個獨立的套件
• XAspect: 以 Aspect-Oriented 的方式,讓
程式碼 reusable 及 maintainable。

• XIntrospect: 把小程式碼包裝成更容易重複
使用的 block (使用 Block-in-Block)。
advice
Traditional

Obj-C
message

Using XSpect

Obj-C
message
advice

method

advice

subtask

subtask

subtask
subtask
Main Task
subtask

subtask

XAspect
XIntrospec

subtask

Main Task
subtask

subtask

subtask
Obj-C
message
advice
advice

method

advice
advice
Obj-C
message
Live Demo
advice
subtask
Main Task
subtask
advice
Obj-C
message

• 程式是由許多 tasks 組成
Main task: 為程式的主架構
Subtasks 應該要很容易的加入或移除

• 我把 subtask 分為兩類:
introspective subtasks
aspect subtasks (advices)

advice
subtask
Main Task
subtask
advice

Introspective tasks:

Aspect advices:

From introspection (inner-spect)

From aspects (outer-spect)

Inside a method

Outside a method

Depending on the main task

Independent jobs (usually)

reusable and maintainable
introspective blocks

reusable and maintainable
aspect categories
XAspect
Using Method Swizzling
(Aspect-Oriented Programming)
利用 Obj-C runtime 的特性,

截

並重新導向 message,以獲得執
行額外程式碼的機會。
Procedure-Oriented
Procedures
(C function calls)

Event	 A

Event	 B

Event	 C

Func

Func

Func

Func

Func

Func

Func

Func

Func

Func

Func

Func

Func

Func

Func
Object-Oriented
Object-Oriented
Class

Class

Class

Class

IMP1
IMP2
IMP3
.

IMP1
IMP2
IMP3
.

IMP1
IMP2
IMP3
.

IMP1
IMP2
IMP3
.

Procedures
(Obj-C messages)

Event	 A

Event	 B

Event	 C

IMP

IMP

IMP

IMP

IMP

IMP

IMP

IMP

IMP

IMP

IMP

IMP

IMP

IMP

IMP

Obj-C
message
Aspect-Oriented
Object-Oriented
Class

Class

Class

Class

IMP1
IMP2
IMP3
.

IMP1
IMP2
IMP3
.

IMP1
IMP2
IMP3
.

IMP1
IMP2
IMP3
.

Procedures
(Obj-C messages)

Event	 A

Event	 B

Event	 C

IMP

IMP

IMP

IMP
Cross-Cutting concerns
Aspect-Oriented
Aspect

B1
B2
B3
.
.

A1

IMP

logging
IMP

A2

IMP

IMP

A3

IMP
security

IMP

Aspect

A1
A2
A3
.
.

Obj-C
message

IMP

B1

IMP
IMP

B2

IMP
IMP

B3
Method Swizzling
Before Swizzling

After Swizzling

Class

Class

SEL A

SEL B

SEL A

SEL B

IMP A

IMP B

IMP A

IMP B
XAspect
Create a recursive invocation
before Method Swizzling
Before Swizzling

After Swizzling
2

Class
SEL A

Class

SEL B

SEL A

SEL B

IMP A

IMP B

1

IMP A

IMP B
Live Demo
// In –viewDidLoad or –application:didFinishLaunchingWithOptions:
User *user = [User new];
NSLog(@"The user is: %@", [user userName]);

@implementation User
- (NSString*)userName{
NSString *userName = @"Xaree Lee";
NSLog(@"I'm %@", userName);
return userName;
}
@end

2013-10-14 23:04:16.454 XSpect[9199:a0b] I'm Xaree Lee
2013-10-14 23:04:16.559 XSpect[9199:a0b] The user is: Xaree Lee
Adding Aspect
// In User+Greeting.m, the Greeting category of User
@implementation User (Greeting)
+ (void)load{
SwapInstanceMethod([self class], @selector(userName),
@selector(Greeting_userName));
}
- (NSString *) Greeting_userName{
// Add before advice here
NSLog(@"==> Hello, what's your name?");
// Invoke recursively
NSString *userName = [self Greeting_userName];
// After advice
NSLog(@"==> Greeting, %@", userName);
return userName;
}
@end

2013-10-14
2013-10-14
2013-10-14
2013-10-14

23:04:16.451
23:04:16.454
23:04:16.558
23:04:16.559

XSpect[9199:a0b]
XSpect[9199:a0b]
XSpect[9199:a0b]
XSpect[9199:a0b]

==>
I'm
==>
The

Hello, what's your name?
Xaree Lee
Greeting, Xaree Lee
user is: Xaree Lee
@implementation User (Greeting)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SwapInstanceMethod([self class], @selector(userName),
@selector(Greeting_userName));
});
}
- (NSString *) Greeting_userName{
// Add before advice here
NSLog(@"==> Hello, what's your name?");
// Invoke recursively
NSString *userName = [self Greeting_userName];
// After advice
NSLog(@"==> Greeting, %@", userName);
return userName;
}
@end

#undef AspectName
#define AspectName Greeting

XAs p e c t
E x te n s i o
n
s t y le

AspectClass(User)
WeaveAspectInstanceMethods(@selector(userName));

AspectImplementation
- (NSString *) Aspect(userName){
// Add before advice here
NSLog(@"==> Hello, what's your name?");
// Invoke recursively
NSString *userName = [self Aspect(userName)];
// After advice
NSLog(@"==> Greeting, %@", userName);
return userName;
}
EndAspect
Class

More
Aspects

SEL A

SEL B
SEL C

IMP A

IMP B

IMP C
IMP B

SEL A

SEL B

SEL C

SEL D
C

IMP A

Add 2nd
Aspect

SEL B

IMP B

IMP C

IMP D
C

Class
Add 3rd
Aspect

Class
results

SEL A

SEL B

SEL C

SEL D
C

@"A"

IMP B
@"B1"
@SEL B
@"B2"

IMP C
@"C1"
@SEL C
@"C2"

IMP C
@"D1"
@SEL D
@"D2"

>
>
>
>
>
>
>

D1
C1
B1
A
B2
C2
D2
Advantages
• Keep OCP principle

(open for extension; closed for modification)

• Encapsulate changes

(write all changes in a aspect file)

• Reusable and maintainable

(you can find all the code in one place)
Disadvantages
• Hard to understand

(if you aren't familiar with AOP)

• Hard to debug

(I might add some code to deal with it)

• Unpredictable loading sequence

(you should use XAspect for the independent
purpose)
XIntrospect
Using Block-in-Block technique

把小片段的程式碼包裝成可重複使
用的 Block,然後 runtime 的時候
再把它們組合起來,並執行。
Why Call it
"Introspect"
並非所有 subtasks 都
是來自獨立的外部觀點
Low Coupling vs High Coupling
subtasks to the main task
1| - (void)appendData:(NSData*)inData{
2|
NSParameterAssert(inData != nil);
3|
NSParameterAssert([inData length]);
4|
if (!inData) {
5|
NSLog(@"inData is nil!");
for guarding and checking
6|
return;
7|
}
8|
if (![inData length]) {
9|
return;
10|
}
11|
NSInteger length = [_data length];
12|
[_lock lock];
for thread safe
13|
[_data appendData:inData];
main task
14|
[_lock unlock];
15|
NSParameterAssert(length != [_data length]);
16| #if DEBUG
for monitoring and analyzing
17|
[TestFlight passCheckpoint:@"APPEND_DATA"];
18| #else
19|
[Flurry logEvent:@"APPEND_DATA"];
20|
id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker];
21|
[tracker send:[[GAIDictionaryBuilder createEventWithCategory:@"data"
withAction:@"append" withLabel:@"user_data" withValue:nil] build]];
22| #endif
23| }

high

?

low
XIntrospect
的要點在於
在 main task 的前後,總是有一
些瑣碎的程式碼是必要的。它們是
完整的程式碼中的一部分。
Blo
ck就像
in是俄 Blo
羅斯 ck
娃娃
Core Block Types
typedef void (^Matryoshka)();
typedef Matryoshka (^IntrospectBlock)(Matryoshka innerBlock);

• Matryoshka:它包含了小片段的程式碼。並可能會在內
部包裝另一個 Matryoshka。在被執行之後,會從最外
層開始一層一層執行程式碼。
(Matryoshka 必須在 IntrospectBlock 內產生)

• IntrospectBlock:實際產生及包裝 Matryoshka 的
Block。它會決定此層的 Matryoshka 的程式碼,並呼叫
更內一層的 Matryoshka。
(IntrospectBlock 是實際上決定程式碼的地方)
Define IntrospectBlock
/** XIntrospectCore Definition **/
typedef void (^Matryoshka)();
typedef Matryoshka (^IntrospectBlock)(Matryoshka innerBlock);
Matryoshka assembleMatryoshka(IntrospectBlock introspection, ... );
/** Declare an IntrospectBlock **/
IntrospectionBlock introspect = ^ Matryoshka(Matryoshka innerBlock){
return ^(){
NSLog(@"before advice");
innerBlock();
NSLog(@"after advice");
};
};
/** Declare another IntrospectBlock **/
IntrospectBlock mainTask = ^ Matryoshka(Matryoshka innerBlock){
return ^(){
NSLog(@"Here's the main task");
};
};
/** XIntrospectCore Definition **/
typedef void (^Matryoshka)();
typedef Matryoshka (^IntrospectBlock)(Matryoshka innerBlock);
Matryoshka assembleMatryoshka(IntrospectBlock introspection, ... );

/** Assemble and invoke the whole matryoshka **/
NSLog(@"Start to assemble a matryoshka");
Matryoshka matryoshka = assembleMatryoshka(introspect,
introspect,
introspect,
mainTask,
nil);
NSLog(@"Prepare to invoke matryoshka");
matryoshka();
NSLog(@"Did invoke matryoshka");

2013-10-15
2013-10-15
2013-10-15
2013-10-15
2013-10-15
2013-10-15
2013-10-15
2013-10-15
2013-10-15
2013-10-15

23:17:09.444
23:17:09.451
23:17:09.452
23:17:09.452
23:17:09.453
23:17:09.453
23:17:09.454
23:17:09.454
23:17:09.455
23:17:09.456

XSpect[10654:a0b]
XSpect[10654:a0b]
XSpect[10654:a0b]
XSpect[10654:a0b]
XSpect[10654:a0b]
XSpect[10654:a0b]
XSpect[10654:a0b]
XSpect[10654:a0b]
XSpect[10654:a0b]
XSpect[10654:a0b]

Start to assemble a matryoshka
Prepare to invoke matryoshka
before advice
before advice
before advice
Here's the main task
after advice
after advice
after advice
Did invoke matryoshka
Advantages
• Keep SRP principle

(single responsibility principle)

• Intuitive coding style

(using the extension macros)

• Reusable and readable

(encapsulate all code in a block)
Disadvantages
• Hard to understand

(if you aren't familiar with Block-in-Block)

• Hard to debug

(I might add some code to deal with it)

• Unpredictable loading sequence

(you should use XAspect for the independent
purpose)
Using	 XSpect	 library	 to
Keep	 those	 code	 cleaner

1| - (void)appendData:(NSData*)inData{
2|
NSParameterAssert(inData != nil);
3|
NSParameterAssert([inData length]);
4|
if (!inData) {
Using XIntrospect
5|
NSLog(@"inData is nil!");
for guarding and checking
6|
return;
7|
}
8|
if (![inData length]) {
9|
return;
Using XIntrospect
10|
}
Or
11|
NSInteger length = [_data length];
Using XAspect
12|
[_lock lock];
for thread safe
13|
[_data appendData:inData];
main task
14|
[_lock unlock];
15|
NSParameterAssert(length != [_data length]);
Using XAspect
16| #if DEBUG
for monitoring and analyzing
17|
[TestFlight passCheckpoint:@"APPEND_DATA"];
18| #else
19|
[Flurry logEvent:@"APPEND_DATA"];
20|
id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker];
21|
[tracker send:[[GAIDictionaryBuilder createEventWithCategory:@"data"
withAction:@"append" withLabel:@"user_data" withValue:nil] build]];
22| #endif
23| }
XSpect
Github: xareelee/XSpect
CocoaPods: preparing
Thanks

Contenu connexe

Tendances

Kotlin – the future of android
Kotlin – the future of androidKotlin – the future of android
Kotlin – the future of androidDJ Rausch
 
tictactoe groovy
tictactoe groovytictactoe groovy
tictactoe groovyPaul King
 
functional groovy
functional groovyfunctional groovy
functional groovyPaul King
 
Java Puzzle
Java PuzzleJava Puzzle
Java PuzzleSFilipp
 
.NET Multithreading and File I/O
.NET Multithreading and File I/O.NET Multithreading and File I/O
.NET Multithreading and File I/OJussi Pohjolainen
 
JDK1.7 features
JDK1.7 featuresJDK1.7 features
JDK1.7 featuresindia_mani
 
Paper id 71201925
Paper id 71201925Paper id 71201925
Paper id 71201925IJRAT
 
(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your GroovyAlonso Torres
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019Leonardo Borges
 
Introduction To Groovy
Introduction To GroovyIntroduction To Groovy
Introduction To Groovymanishkp84
 
Java Performance Puzzlers
Java Performance PuzzlersJava Performance Puzzlers
Java Performance PuzzlersDoug Hawkins
 
Non-blocking Michael-Scott queue algorithm
Non-blocking Michael-Scott queue algorithmNon-blocking Michael-Scott queue algorithm
Non-blocking Michael-Scott queue algorithmAlexey Fyodorov
 
Douglas Crockford: Serversideness
Douglas Crockford: ServersidenessDouglas Crockford: Serversideness
Douglas Crockford: ServersidenessWebExpo
 

Tendances (20)

Kotlin – the future of android
Kotlin – the future of androidKotlin – the future of android
Kotlin – the future of android
 
tictactoe groovy
tictactoe groovytictactoe groovy
tictactoe groovy
 
Nx tutorial basics
Nx tutorial basicsNx tutorial basics
Nx tutorial basics
 
Java puzzles
Java puzzlesJava puzzles
Java puzzles
 
Java Puzzlers
Java PuzzlersJava Puzzlers
Java Puzzlers
 
functional groovy
functional groovyfunctional groovy
functional groovy
 
Java Puzzle
Java PuzzleJava Puzzle
Java Puzzle
 
bluespec talk
bluespec talkbluespec talk
bluespec talk
 
Groovy
GroovyGroovy
Groovy
 
.NET Multithreading and File I/O
.NET Multithreading and File I/O.NET Multithreading and File I/O
.NET Multithreading and File I/O
 
JDK1.7 features
JDK1.7 featuresJDK1.7 features
JDK1.7 features
 
JVM Mechanics
JVM MechanicsJVM Mechanics
JVM Mechanics
 
Paper id 71201925
Paper id 71201925Paper id 71201925
Paper id 71201925
 
(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019
 
Enter The Matrix
Enter The MatrixEnter The Matrix
Enter The Matrix
 
Introduction To Groovy
Introduction To GroovyIntroduction To Groovy
Introduction To Groovy
 
Java Performance Puzzlers
Java Performance PuzzlersJava Performance Puzzlers
Java Performance Puzzlers
 
Non-blocking Michael-Scott queue algorithm
Non-blocking Michael-Scott queue algorithmNon-blocking Michael-Scott queue algorithm
Non-blocking Michael-Scott queue algorithm
 
Douglas Crockford: Serversideness
Douglas Crockford: ServersidenessDouglas Crockford: Serversideness
Douglas Crockford: Serversideness
 

En vedette

flyingV Laravel & AWS 經驗分享
flyingV Laravel & AWS 經驗分享flyingV Laravel & AWS 經驗分享
flyingV Laravel & AWS 經驗分享Eugene Wang
 
Real-time Big Data Analytics Engine using Impala
Real-time Big Data Analytics Engine using ImpalaReal-time Big Data Analytics Engine using Impala
Real-time Big Data Analytics Engine using ImpalaJason Shih
 
Software Development Model for Startups
Software Development Model for StartupsSoftware Development Model for Startups
Software Development Model for StartupsMartin Verrev
 
簡報藝術-建構故事
簡報藝術-建構故事 簡報藝術-建構故事
簡報藝術-建構故事 Chuck Chiang
 
About Mobile Web Development Thing
About Mobile Web Development ThingAbout Mobile Web Development Thing
About Mobile Web Development ThingYu-Wei Chuang
 
Hooked Workshop
Hooked WorkshopHooked Workshop
Hooked WorkshopNir Eyal
 
Dropbox Startup Lessons Learned
Dropbox Startup Lessons LearnedDropbox Startup Lessons Learned
Dropbox Startup Lessons Learnedgueste94e4c
 

En vedette (7)

flyingV Laravel & AWS 經驗分享
flyingV Laravel & AWS 經驗分享flyingV Laravel & AWS 經驗分享
flyingV Laravel & AWS 經驗分享
 
Real-time Big Data Analytics Engine using Impala
Real-time Big Data Analytics Engine using ImpalaReal-time Big Data Analytics Engine using Impala
Real-time Big Data Analytics Engine using Impala
 
Software Development Model for Startups
Software Development Model for StartupsSoftware Development Model for Startups
Software Development Model for Startups
 
簡報藝術-建構故事
簡報藝術-建構故事 簡報藝術-建構故事
簡報藝術-建構故事
 
About Mobile Web Development Thing
About Mobile Web Development ThingAbout Mobile Web Development Thing
About Mobile Web Development Thing
 
Hooked Workshop
Hooked WorkshopHooked Workshop
Hooked Workshop
 
Dropbox Startup Lessons Learned
Dropbox Startup Lessons LearnedDropbox Startup Lessons Learned
Dropbox Startup Lessons Learned
 

Similaire à XSpect, a lightweight library to make your code reusable and maintainable.

ECMAScript2015
ECMAScript2015ECMAScript2015
ECMAScript2015qmmr
 
Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCAWhymca
 
Cocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design PatternsCocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design PatternsMaciej Burda
 
The mighty js_function
The mighty js_functionThe mighty js_function
The mighty js_functiontimotheeg
 
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)Sarp Erdag
 
ES6 Simplified
ES6 SimplifiedES6 Simplified
ES6 SimplifiedCarlos Ble
 
連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」matuura_core
 
M 0 1 2 3 4 5 6 7 0.pdf
 M  0  1  2  3  4  5  6  7    0.pdf M  0  1  2  3  4  5  6  7    0.pdf
M 0 1 2 3 4 5 6 7 0.pdfajay1317
 
Webエンジニアから見たiOS5
Webエンジニアから見たiOS5Webエンジニアから見たiOS5
Webエンジニアから見たiOS5Satoshi Asano
 
Data structures lab manual
Data structures lab manualData structures lab manual
Data structures lab manualSyed Mustafa
 
High Performance Core Data
High Performance Core DataHigh Performance Core Data
High Performance Core DataMatthew Morey
 
ios,objective tutorial
ios,objective tutorial ios,objective tutorial
ios,objective tutorial Bhavik Patel
 
in this assignment you are asked to write a simple driver program an.pdf
in this assignment you are asked to write a simple driver program an.pdfin this assignment you are asked to write a simple driver program an.pdf
in this assignment you are asked to write a simple driver program an.pdfmichardsonkhaicarr37
 
Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()Miłosz Sobczak
 
Writing SOLID C++ [gbgcpp meetup @ Zenseact]
Writing SOLID C++ [gbgcpp meetup @ Zenseact]Writing SOLID C++ [gbgcpp meetup @ Zenseact]
Writing SOLID C++ [gbgcpp meetup @ Zenseact]Dimitrios Platis
 
Users' Data Security in iOS Applications
Users' Data Security in iOS ApplicationsUsers' Data Security in iOS Applications
Users' Data Security in iOS ApplicationsStanfy
 
Productaccess m
Productaccess mProductaccess m
Productaccess mAdil Usman
 

Similaire à XSpect, a lightweight library to make your code reusable and maintainable. (20)

FMDB - SLC-Cocoaheads
FMDB - SLC-CocoaheadsFMDB - SLC-Cocoaheads
FMDB - SLC-Cocoaheads
 
ECMAScript2015
ECMAScript2015ECMAScript2015
ECMAScript2015
 
Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCA
 
Cocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design PatternsCocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design Patterns
 
The mighty js_function
The mighty js_functionThe mighty js_function
The mighty js_function
 
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
 
ES6 Simplified
ES6 SimplifiedES6 Simplified
ES6 Simplified
 
連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」
 
M 0 1 2 3 4 5 6 7 0.pdf
 M  0  1  2  3  4  5  6  7    0.pdf M  0  1  2  3  4  5  6  7    0.pdf
M 0 1 2 3 4 5 6 7 0.pdf
 
Webエンジニアから見たiOS5
Webエンジニアから見たiOS5Webエンジニアから見たiOS5
Webエンジニアから見たiOS5
 
C arrays
C arraysC arrays
C arrays
 
Data structures lab manual
Data structures lab manualData structures lab manual
Data structures lab manual
 
High Performance Core Data
High Performance Core DataHigh Performance Core Data
High Performance Core Data
 
ios,objective tutorial
ios,objective tutorial ios,objective tutorial
ios,objective tutorial
 
in this assignment you are asked to write a simple driver program an.pdf
in this assignment you are asked to write a simple driver program an.pdfin this assignment you are asked to write a simple driver program an.pdf
in this assignment you are asked to write a simple driver program an.pdf
 
Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()
 
Writing SOLID C++ [gbgcpp meetup @ Zenseact]
Writing SOLID C++ [gbgcpp meetup @ Zenseact]Writing SOLID C++ [gbgcpp meetup @ Zenseact]
Writing SOLID C++ [gbgcpp meetup @ Zenseact]
 
Sequelize
SequelizeSequelize
Sequelize
 
Users' Data Security in iOS Applications
Users' Data Security in iOS ApplicationsUsers' Data Security in iOS Applications
Users' Data Security in iOS Applications
 
Productaccess m
Productaccess mProductaccess m
Productaccess m
 

Dernier

Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGSujit Pal
 

Dernier (20)

Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAG
 

XSpect, a lightweight library to make your code reusable and maintainable.

  • 1. XSpect Makes code reusable and maintainable 2013/10/17 李岡諭 Xaree Lee (leondemon) xareelee@gmail.com
  • 2. Previously on Cocoaheads@Taipei Zonble's talk (about AOP) http://goo.gl/4Rlbb2
  • 4. Life should be simple, but... 1| 2| 3| - (void)appendData:(NSData*)inData{ [_data appendData:inData]; }
  • 5. Welcome to real life 1| - (void)appendData:(NSData*)inData{ 2| NSParameterAssert(inData != nil); 3| NSParameterAssert([inData length]); 4| if (!inData) { 5| NSLog(@"inData is nil!"); for guarding and checking 6| return; 7| } 8| if (![inData length]) { 9| return; 10| } 11| NSInteger length = [_data length]; 12| [_lock lock]; for thread safe 13| [_data appendData:inData]; main task 14| [_lock unlock]; 15| NSParameterAssert(length != [_data length]); 16| #if DEBUG for monitoring and analyzing 17| [TestFlight passCheckpoint:@"APPEND_DATA"]; 18| #else 19| [Flurry logEvent:@"APPEND_DATA"]; 20| id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker]; 21| [tracker send:[[GAIDictionaryBuilder createEventWithCategory:@"data" withAction:@"append" withLabel:@"user_data" withValue:nil] build]]; 22| #endif 23| }
  • 6. You add lots of code for •確定傳入參數 •確定有插入資料 •加 lock •加 Debug Log •加 TestFlight Log、Flurry Log... ...and everywhere!
  • 7. XSpect Xaree's Spect library spect: look, see http://www.prefixsuffix.com
  • 8. XSpect 包含了 2 個獨立的套件 • XAspect: 以 Aspect-Oriented 的方式,讓 程式碼 reusable 及 maintainable。 • XIntrospect: 把小程式碼包裝成更容易重複 使用的 block (使用 Block-in-Block)。
  • 11. advice subtask Main Task subtask advice Obj-C message • 程式是由許多 tasks 組成 Main task: 為程式的主架構 Subtasks 應該要很容易的加入或移除 • 我把 subtask 分為兩類: introspective subtasks aspect subtasks (advices) advice subtask Main Task subtask advice Introspective tasks: Aspect advices: From introspection (inner-spect) From aspects (outer-spect) Inside a method Outside a method Depending on the main task Independent jobs (usually) reusable and maintainable introspective blocks reusable and maintainable aspect categories
  • 12. XAspect Using Method Swizzling (Aspect-Oriented Programming) 利用 Obj-C runtime 的特性, 截 並重新導向 message,以獲得執 行額外程式碼的機會。
  • 13. Procedure-Oriented Procedures (C function calls) Event A Event B Event C Func Func Func Func Func Func Func Func Func Func Func Func Func Func Func
  • 15. Aspect-Oriented Object-Oriented Class Class Class Class IMP1 IMP2 IMP3 . IMP1 IMP2 IMP3 . IMP1 IMP2 IMP3 . IMP1 IMP2 IMP3 . Procedures (Obj-C messages) Event A Event B Event C IMP IMP IMP IMP Cross-Cutting concerns Aspect-Oriented Aspect B1 B2 B3 . . A1 IMP logging IMP A2 IMP IMP A3 IMP security IMP Aspect A1 A2 A3 . . Obj-C message IMP B1 IMP IMP B2 IMP IMP B3
  • 16. Method Swizzling Before Swizzling After Swizzling Class Class SEL A SEL B SEL A SEL B IMP A IMP B IMP A IMP B
  • 17. XAspect Create a recursive invocation before Method Swizzling Before Swizzling After Swizzling 2 Class SEL A Class SEL B SEL A SEL B IMP A IMP B 1 IMP A IMP B
  • 18. Live Demo // In –viewDidLoad or –application:didFinishLaunchingWithOptions: User *user = [User new]; NSLog(@"The user is: %@", [user userName]); @implementation User - (NSString*)userName{ NSString *userName = @"Xaree Lee"; NSLog(@"I'm %@", userName); return userName; } @end 2013-10-14 23:04:16.454 XSpect[9199:a0b] I'm Xaree Lee 2013-10-14 23:04:16.559 XSpect[9199:a0b] The user is: Xaree Lee
  • 19. Adding Aspect // In User+Greeting.m, the Greeting category of User @implementation User (Greeting) + (void)load{ SwapInstanceMethod([self class], @selector(userName), @selector(Greeting_userName)); } - (NSString *) Greeting_userName{ // Add before advice here NSLog(@"==> Hello, what's your name?"); // Invoke recursively NSString *userName = [self Greeting_userName]; // After advice NSLog(@"==> Greeting, %@", userName); return userName; } @end 2013-10-14 2013-10-14 2013-10-14 2013-10-14 23:04:16.451 23:04:16.454 23:04:16.558 23:04:16.559 XSpect[9199:a0b] XSpect[9199:a0b] XSpect[9199:a0b] XSpect[9199:a0b] ==> I'm ==> The Hello, what's your name? Xaree Lee Greeting, Xaree Lee user is: Xaree Lee
  • 20. @implementation User (Greeting) + (void)load{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ SwapInstanceMethod([self class], @selector(userName), @selector(Greeting_userName)); }); } - (NSString *) Greeting_userName{ // Add before advice here NSLog(@"==> Hello, what's your name?"); // Invoke recursively NSString *userName = [self Greeting_userName]; // After advice NSLog(@"==> Greeting, %@", userName); return userName; } @end #undef AspectName #define AspectName Greeting XAs p e c t E x te n s i o n s t y le AspectClass(User) WeaveAspectInstanceMethods(@selector(userName)); AspectImplementation - (NSString *) Aspect(userName){ // Add before advice here NSLog(@"==> Hello, what's your name?"); // Invoke recursively NSString *userName = [self Aspect(userName)]; // After advice NSLog(@"==> Greeting, %@", userName); return userName; } EndAspect
  • 21. Class More Aspects SEL A SEL B SEL C IMP A IMP B IMP C IMP B SEL A SEL B SEL C SEL D C IMP A Add 2nd Aspect SEL B IMP B IMP C IMP D C Class Add 3rd Aspect Class results SEL A SEL B SEL C SEL D C @"A" IMP B @"B1" @SEL B @"B2" IMP C @"C1" @SEL C @"C2" IMP C @"D1" @SEL D @"D2" > > > > > > > D1 C1 B1 A B2 C2 D2
  • 22. Advantages • Keep OCP principle (open for extension; closed for modification) • Encapsulate changes (write all changes in a aspect file) • Reusable and maintainable (you can find all the code in one place)
  • 23. Disadvantages • Hard to understand (if you aren't familiar with AOP) • Hard to debug (I might add some code to deal with it) • Unpredictable loading sequence (you should use XAspect for the independent purpose)
  • 24. XIntrospect Using Block-in-Block technique 把小片段的程式碼包裝成可重複使 用的 Block,然後 runtime 的時候 再把它們組合起來,並執行。
  • 25. Why Call it "Introspect" 並非所有 subtasks 都 是來自獨立的外部觀點
  • 26. Low Coupling vs High Coupling subtasks to the main task 1| - (void)appendData:(NSData*)inData{ 2| NSParameterAssert(inData != nil); 3| NSParameterAssert([inData length]); 4| if (!inData) { 5| NSLog(@"inData is nil!"); for guarding and checking 6| return; 7| } 8| if (![inData length]) { 9| return; 10| } 11| NSInteger length = [_data length]; 12| [_lock lock]; for thread safe 13| [_data appendData:inData]; main task 14| [_lock unlock]; 15| NSParameterAssert(length != [_data length]); 16| #if DEBUG for monitoring and analyzing 17| [TestFlight passCheckpoint:@"APPEND_DATA"]; 18| #else 19| [Flurry logEvent:@"APPEND_DATA"]; 20| id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker]; 21| [tracker send:[[GAIDictionaryBuilder createEventWithCategory:@"data" withAction:@"append" withLabel:@"user_data" withValue:nil] build]]; 22| #endif 23| } high ? low
  • 27. XIntrospect 的要點在於 在 main task 的前後,總是有一 些瑣碎的程式碼是必要的。它們是 完整的程式碼中的一部分。
  • 29. Core Block Types typedef void (^Matryoshka)(); typedef Matryoshka (^IntrospectBlock)(Matryoshka innerBlock); • Matryoshka:它包含了小片段的程式碼。並可能會在內 部包裝另一個 Matryoshka。在被執行之後,會從最外 層開始一層一層執行程式碼。 (Matryoshka 必須在 IntrospectBlock 內產生) • IntrospectBlock:實際產生及包裝 Matryoshka 的 Block。它會決定此層的 Matryoshka 的程式碼,並呼叫 更內一層的 Matryoshka。 (IntrospectBlock 是實際上決定程式碼的地方)
  • 30. Define IntrospectBlock /** XIntrospectCore Definition **/ typedef void (^Matryoshka)(); typedef Matryoshka (^IntrospectBlock)(Matryoshka innerBlock); Matryoshka assembleMatryoshka(IntrospectBlock introspection, ... ); /** Declare an IntrospectBlock **/ IntrospectionBlock introspect = ^ Matryoshka(Matryoshka innerBlock){ return ^(){ NSLog(@"before advice"); innerBlock(); NSLog(@"after advice"); }; }; /** Declare another IntrospectBlock **/ IntrospectBlock mainTask = ^ Matryoshka(Matryoshka innerBlock){ return ^(){ NSLog(@"Here's the main task"); }; };
  • 31. /** XIntrospectCore Definition **/ typedef void (^Matryoshka)(); typedef Matryoshka (^IntrospectBlock)(Matryoshka innerBlock); Matryoshka assembleMatryoshka(IntrospectBlock introspection, ... ); /** Assemble and invoke the whole matryoshka **/ NSLog(@"Start to assemble a matryoshka"); Matryoshka matryoshka = assembleMatryoshka(introspect, introspect, introspect, mainTask, nil); NSLog(@"Prepare to invoke matryoshka"); matryoshka(); NSLog(@"Did invoke matryoshka"); 2013-10-15 2013-10-15 2013-10-15 2013-10-15 2013-10-15 2013-10-15 2013-10-15 2013-10-15 2013-10-15 2013-10-15 23:17:09.444 23:17:09.451 23:17:09.452 23:17:09.452 23:17:09.453 23:17:09.453 23:17:09.454 23:17:09.454 23:17:09.455 23:17:09.456 XSpect[10654:a0b] XSpect[10654:a0b] XSpect[10654:a0b] XSpect[10654:a0b] XSpect[10654:a0b] XSpect[10654:a0b] XSpect[10654:a0b] XSpect[10654:a0b] XSpect[10654:a0b] XSpect[10654:a0b] Start to assemble a matryoshka Prepare to invoke matryoshka before advice before advice before advice Here's the main task after advice after advice after advice Did invoke matryoshka
  • 32. Advantages • Keep SRP principle (single responsibility principle) • Intuitive coding style (using the extension macros) • Reusable and readable (encapsulate all code in a block)
  • 33. Disadvantages • Hard to understand (if you aren't familiar with Block-in-Block) • Hard to debug (I might add some code to deal with it) • Unpredictable loading sequence (you should use XAspect for the independent purpose)
  • 34. Using XSpect library to Keep those code cleaner 1| - (void)appendData:(NSData*)inData{ 2| NSParameterAssert(inData != nil); 3| NSParameterAssert([inData length]); 4| if (!inData) { Using XIntrospect 5| NSLog(@"inData is nil!"); for guarding and checking 6| return; 7| } 8| if (![inData length]) { 9| return; Using XIntrospect 10| } Or 11| NSInteger length = [_data length]; Using XAspect 12| [_lock lock]; for thread safe 13| [_data appendData:inData]; main task 14| [_lock unlock]; 15| NSParameterAssert(length != [_data length]); Using XAspect 16| #if DEBUG for monitoring and analyzing 17| [TestFlight passCheckpoint:@"APPEND_DATA"]; 18| #else 19| [Flurry logEvent:@"APPEND_DATA"]; 20| id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker]; 21| [tracker send:[[GAIDictionaryBuilder createEventWithCategory:@"data" withAction:@"append" withLabel:@"user_data" withValue:nil] build]]; 22| #endif 23| }